-/*
- * mini-llvm.c: llvm "Backend" for the mono JIT
+/**
+ * \file
+ * llvm "Backend" for the mono JIT
*
* Copyright 2009-2011 Novell Inc (http://www.novell.com)
* Copyright 2011 Xamarin Inc (http://www.xamarin.com)
* Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
-#include "mini.h"
+#include "config.h"
+
#include <mono/metadata/debug-helpers.h>
-#include <mono/metadata/debug-mono-symfile.h>
+#include <mono/metadata/debug-internals.h>
#include <mono/metadata/mempool-internals.h>
#include <mono/metadata/environment.h>
#include <mono/metadata/object-internals.h>
#include "aot-compiler.h"
#include "mini-llvm.h"
+#ifndef DISABLE_JIT
+
#ifdef __MINGW32__
#include <stddef.h>
LLVMValueRef rgctx_arg;
LLVMValueRef this_arg;
LLVMTypeRef *vreg_types;
+ gboolean *is_vphi;
LLVMTypeRef method_type;
LLVMBasicBlockRef init_bb, inited_bb;
gboolean *is_dead;
return LLVMVectorType (LLVMInt8Type (), 16);
} else if (!strcmp (klass->name, "Vector16b")) {
return LLVMVectorType (LLVMInt8Type (), 16);
+ } else if (!strcmp (klass->name, "Vector2")) {
+ /* System.Numerics */
+ return LLVMVectorType (LLVMFloatType (), 4);
+ } else if (!strcmp (klass->name, "Vector3")) {
+ return LLVMVectorType (LLVMFloatType (), 4);
+ } else if (!strcmp (klass->name, "Vector4")) {
+ return LLVMVectorType (LLVMFloatType (), 4);
+ } else if (!strcmp (klass->name, "Vector`1")) {
+ MonoType *etype = mono_class_get_generic_class (klass)->context.class_inst->type_argv [0];
+ switch (etype->type) {
+ case MONO_TYPE_I1:
+ case MONO_TYPE_U1:
+ return LLVMVectorType (LLVMInt8Type (), 16);
+ case MONO_TYPE_I2:
+ case MONO_TYPE_U2:
+ return LLVMVectorType (LLVMInt16Type (), 8);
+ case MONO_TYPE_I4:
+ case MONO_TYPE_U4:
+ return LLVMVectorType (LLVMInt32Type (), 4);
+ case MONO_TYPE_I8:
+ case MONO_TYPE_U8:
+ return LLVMVectorType (LLVMInt64Type (), 2);
+ case MONO_TYPE_R4:
+ return LLVMVectorType (LLVMFloatType (), 4);
+ case MONO_TYPE_R8:
+ return LLVMVectorType (LLVMDoubleType (), 2);
+ default:
+ g_assert_not_reached ();
+ return NULL;
+ }
} else {
printf ("%s\n", klass->name);
NOT_IMPLEMENTED;
* This is needed on arm64 where HFAs are returned in
* registers.
*/
+ /* SIMD types have size 16 in mono_class_value_size () */
+ if (klass->simd_type)
+ nfields = 16/ esize;
size = nfields;
eltypes = g_new (LLVMTypeRef, size);
for (i = 0; i < size; ++i)
return LLVMInt16Type ();
case MONO_TYPE_U4:
return LLVMInt32Type ();
- case MONO_TYPE_BOOLEAN:
- return LLVMInt8Type ();
case MONO_TYPE_I8:
case MONO_TYPE_U8:
return LLVMInt64Type ();
- case MONO_TYPE_CHAR:
- return LLVMInt16Type ();
case MONO_TYPE_R4:
return LLVMFloatType ();
case MONO_TYPE_R8:
case MONO_TYPE_U:
return IntPtrType ();
case MONO_TYPE_OBJECT:
- case MONO_TYPE_CLASS:
- case MONO_TYPE_ARRAY:
- case MONO_TYPE_SZARRAY:
- case MONO_TYPE_STRING:
case MONO_TYPE_PTR:
return ObjRefType ();
case MONO_TYPE_VAR:
return "llvm.x86.sse2.pmulh.w";
case OP_PMULW_HIGH_UN:
return "llvm.x86.sse2.pmulhu.w";
+ case OP_DPPS:
+ return "llvm.x86.sse41.dpps";
#endif
default:
g_assert_not_reached ();
pindex ++;
break;
case LLVMArgAsIArgs:
- param_types [pindex] = LLVMArrayType (IntPtrType (), ainfo->nslots);
+ if (ainfo->esize == 8)
+ param_types [pindex] = LLVMArrayType (LLVMInt64Type (), ainfo->nslots);
+ else
+ param_types [pindex] = LLVMArrayType (IntPtrType (), ainfo->nslots);
pindex ++;
break;
case LLVMArgVtypeByRef:
}
case LLVMArgAsIArgs:
g_assert (addresses [reg]);
- args [pindex] = LLVMBuildLoad (ctx->builder, convert (ctx, addresses [reg], LLVMPointerType (LLVMArrayType (IntPtrType (), ainfo->nslots), 0)), "");
+ if (ainfo->esize == 8)
+ args [pindex] = LLVMBuildLoad (ctx->builder, convert (ctx, addresses [reg], LLVMPointerType (LLVMArrayType (LLVMInt64Type (), ainfo->nslots), 0)), "");
+ else
+ args [pindex] = LLVMBuildLoad (ctx->builder, convert (ctx, addresses [reg], LLVMPointerType (LLVMArrayType (IntPtrType (), ainfo->nslots), 0)), "");
break;
case LLVMArgVtypeAsScalar:
g_assert_not_reached ();
lcall = emit_call (ctx, bb, &builder, callee, args, LLVMCountParamTypes (llvm_sig));
+ if (ins->opcode != OP_TAILCALL && LLVMGetInstructionOpcode (lcall) == LLVMCall)
+ mono_llvm_set_call_notail (lcall);
+
/*
* Modify cconv and parameter attributes to pass rgctx/imt correctly.
*/
LLVMValueRef switch_ins = LLVMBuildSwitch (lpadBuilder, match, resume_bb, group_size);
// else move to that target bb
- for (int i=0; i < group_size; i++) {
+ for (int i = 0; i < group_size; i++) {
MonoExceptionClause *clause = group_start + i;
int clause_index = clause - cfg->header->clauses;
MonoBasicBlock *handler_bb = (MonoBasicBlock*)g_hash_table_lookup (ctx->clause_to_handler, GINT_TO_POINTER (clause_index));
break;
}
- case OP_TLS_GET_REG: {
-#if defined(TARGET_AMD64) && defined(__linux__)
- // 257 == FS segment register
- LLVMTypeRef ptrtype = LLVMPointerType (IntPtrType (), 257);
- values [ins->dreg] = LLVMBuildLoad (builder, LLVMBuildIntToPtr (builder, convert (ctx, lhs, LLVMInt64Type ()), ptrtype, ""), "");
-#elif defined(TARGET_AMD64) && defined(TARGET_OSX)
- /* See emit_tls_get_reg () */
- // 256 == GS segment register
- LLVMTypeRef ptrtype = LLVMPointerType (IntPtrType (), 256);
- values [ins->dreg] = LLVMBuildLoad (builder, LLVMBuildIntToPtr (builder, convert (ctx, lhs, LLVMInt32Type ()), ptrtype, ""), "");
-#else
- set_failure (ctx, "opcode tls-get");
- break;
-#endif
- break;
- }
-
- case OP_TLS_SET_REG: {
-#if defined(TARGET_AMD64) && defined(TARGET_OSX)
- /* See emit_tls_get_reg () */
- // 256 == GS segment register
- LLVMTypeRef ptrtype = LLVMPointerType (IntPtrType (), 256);
- LLVMBuildStore (builder, convert (ctx, lhs, IntPtrType ()), LLVMBuildIntToPtr (builder, convert (ctx, rhs, LLVMInt32Type ()), ptrtype, ""));
-#else
- set_failure (ctx, "opcode tls-set-reg");
- break;
-#endif
- break;
- }
case OP_GC_SAFE_POINT: {
LLVMValueRef val, cmp, callee;
LLVMBasicBlockRef poll_bb, cont_bb;
const char *name = (const char*)ins->inst_p0;
LLVMValueRef var;
- if (!ctx->module->objc_selector_to_var)
+ if (!ctx->module->objc_selector_to_var) {
ctx->module->objc_selector_to_var = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
+ LLVMValueRef info_var = LLVMAddGlobal (ctx->lmodule, LLVMArrayType (LLVMInt8Type (), 8), "@OBJC_IMAGE_INFO");
+ int32_t objc_imageinfo [] = { 0, 16 };
+ LLVMSetInitializer (info_var, mono_llvm_create_constant_data_array ((uint8_t *) &objc_imageinfo, 8));
+ LLVMSetLinkage (info_var, LLVMPrivateLinkage);
+ LLVMSetExternallyInitialized (info_var, TRUE);
+ LLVMSetSection (info_var, "__DATA, __objc_imageinfo,regular,no_dead_strip");
+ LLVMSetAlignment (info_var, sizeof (mgreg_t));
+ mark_as_used (ctx->module, info_var);
+ }
+
var = g_hash_table_lookup (ctx->module->objc_selector_to_var, name);
if (!var) {
LLVMValueRef indexes [16];
values [ins->dreg] = LLVMBuildInsertElement (builder, values [ins->sreg1], convert (ctx, values [ins->sreg2], LLVMDoubleType ()), LLVMConstInt (LLVMInt32Type (), ins->inst_c0, FALSE), dname);
break;
-#if 0
- // Requires a later llvm version
+#if LLVM_API_VERSION > 100
case OP_CVTDQ2PD: {
LLVMValueRef indexes [16];
break;
#endif
+#if LLVM_API_VERSION <= 100
case OP_CVTDQ2PD:
+ case OP_CVTPS2PD:
+ case OP_CVTTPS2DQ:
+#endif
case OP_CVTDQ2PS:
case OP_CVTPD2DQ:
case OP_CVTPS2DQ:
case OP_CVTPD2PS:
- case OP_CVTPS2PD:
case OP_CVTTPD2DQ:
- case OP_CVTTPS2DQ:
case OP_EXTRACT_MASK:
case OP_SQRTPS:
case OP_SQRTPD:
break;
}
+ case OP_DPPS: {
+ LLVMValueRef args [3];
+
+ args [0] = lhs;
+ args [1] = rhs;
+ /* 0xf1 == multiply all 4 elements, add them together, and store the result to the lowest element */
+ args [2] = LLVMConstInt (LLVMInt32Type (), 0xf1, FALSE);
+
+ values [ins->dreg] = LLVMBuildCall (builder, get_intrinsic (ctx, simd_op_to_intrins (ins->opcode)), args, 3, dname);
+ break;
+ }
+
#endif /* SIMD */
case OP_DUMMY_USE:
/* Convert the value to the type required by phi nodes */
if (spec [MONO_INST_DEST] != ' ' && !MONO_IS_STORE_MEMBASE (ins) && ctx->vreg_types [ins->dreg]) {
- if (!values [ins->dreg])
+ if (ctx->is_vphi [ins->dreg])
/* vtypes */
values [ins->dreg] = addresses [ins->dreg];
else
g_free (ctx->values);
g_free (ctx->addresses);
g_free (ctx->vreg_types);
+ g_free (ctx->is_vphi);
g_free (ctx->vreg_cli_types);
g_free (ctx->is_dead);
g_free (ctx->unreachable);
*/
ctx->addresses = g_new0 (LLVMValueRef, cfg->next_vreg);
ctx->vreg_types = g_new0 (LLVMTypeRef, cfg->next_vreg);
+ ctx->is_vphi = g_new0 (gboolean, cfg->next_vreg);
ctx->vreg_cli_types = g_new0 (MonoType*, cfg->next_vreg);
ctx->phi_values = g_ptr_array_sized_new (256);
/*
static int count = 0;
count ++;
- if (g_getenv ("LLVM_COUNT")) {
- if (count == atoi (g_getenv ("LLVM_COUNT"))) {
+ char *llvm_count_str = g_getenv ("LLVM_COUNT");
+ if (llvm_count_str) {
+ int lcount = atoi (llvm_count_str);
+ g_free (llvm_count_str);
+ if (count == lcount) {
printf ("LAST: %s\n", mono_method_full_name (cfg->method, TRUE));
fflush (stdout);
last = TRUE;
}
- if (count > atoi (g_getenv ("LLVM_COUNT"))) {
+ if (count > lcount) {
set_failure (ctx, "count");
return;
}
for (i = 0; i < ins->inst_phi_args [0]; i++) {
int sreg1 = ins->inst_phi_args [i + 1];
- if (sreg1 != -1)
+ if (sreg1 != -1) {
+ if (ins->opcode == OP_VPHI)
+ ctx->is_vphi [sreg1] = TRUE;
ctx->vreg_types [sreg1] = phi_type;
+ }
}
break;
}
LLVMValueRef switch_ins = (LLVMValueRef)l->data;
GSList *bb_list = info->call_handler_return_bbs;
- for (i = 0; i < g_slist_length (bb_list); ++i)
- LLVMAddCase (switch_ins, LLVMConstInt (LLVMInt32Type (), i + 1, FALSE), (LLVMBasicBlockRef)(g_slist_nth (bb_list, i)->data));
+ GSList *bb_list_iter;
+ i = 0;
+ for (bb_list_iter = bb_list; bb_list_iter; bb_list_iter = g_slist_next (bb_list_iter)) {
+ LLVMAddCase (switch_ins, LLVMConstInt (LLVMInt32Type (), i + 1, FALSE), (LLVMBasicBlockRef)bb_list_iter->data);
+ i ++;
+ }
}
}
INTRINS_SSE_PSUBUSB,
INTRINS_SSE_PAVGB,
INTRINS_SSE_PAUSE,
+ INTRINS_SSE_DPPS,
#endif
INTRINS_NUM
} IntrinsicId;
{INTRINS_SSE_PADDUSB, "llvm.x86.sse2.paddus.b"},
{INTRINS_SSE_PSUBUSB, "llvm.x86.sse2.psubus.b"},
{INTRINS_SSE_PAVGB, "llvm.x86.sse2.pavg.b"},
- {INTRINS_SSE_PAUSE, "llvm.x86.sse2.pause"}
+ {INTRINS_SSE_PAUSE, "llvm.x86.sse2.pause"},
+ {INTRINS_SSE_DPPS, "llvm.x86.sse41.dpps"}
#endif
};
case INTRINS_SSE_PAUSE:
AddFunc (module, "llvm.x86.sse2.pause", LLVMVoidType (), NULL, 0);
break;
+ case INTRINS_SSE_DPPS:
+ ret_type = type_to_simd_type (MONO_TYPE_R4);
+ arg_types [0] = type_to_simd_type (MONO_TYPE_R4);
+ arg_types [1] = type_to_simd_type (MONO_TYPE_R4);
+ arg_types [2] = LLVMInt32Type ();
+ AddFunc (module, name, ret_type, arg_types, 3);
+ break;
#endif
default:
g_assert_not_reached ();
module->llvm_only = llvm_only;
/* The first few entries are reserved */
module->max_got_offset = 16;
- module->context = LLVMContextCreate ();
+ module->context = LLVMGetGlobalContext ();
if (llvm_only)
/* clang ignores our debug info because it has an invalid version */
if (!minfo)
return NULL;
- mono_debug_symfile_get_seq_points (minfo, &source_file, NULL, NULL, &sym_seq_points, &n_seq_points);
+ mono_debug_get_seq_points (minfo, &source_file, NULL, NULL, &sym_seq_points, &n_seq_points);
if (!source_file)
source_file = g_strdup ("<unknown>");
dir = g_path_get_dirname (source_file);
MonoDebugSourceLocation *loc;
LLVMValueRef loc_md;
- loc = mono_debug_symfile_lookup_location (ctx->minfo, cil_code - cfg->header->code);
+ loc = mono_debug_method_lookup_location (ctx->minfo, cil_code - cfg->header->code);
if (loc) {
#if LLVM_API_VERSION > 100
loc_md = LLVMMDNode (md_args, nmd_args);
LLVMSetCurrentDebugLocation (builder, loc_md);
#endif
- mono_debug_symfile_free_location (loc);
+ mono_debug_free_source_location (loc);
}
}
}
* code.
* - use pointer types to help optimizations.
*/
+
+#else /* DISABLE_JIT */
+
+void
+mono_llvm_cleanup (void)
+{
+}
+
+void
+mono_llvm_free_domain_info (MonoDomain *domain)
+{
+}
+
+void
+mono_llvm_init (void)
+{
+}
+
+void
+default_mono_llvm_unhandled_exception (void)
+{
+}
+
+#endif /* DISABLE_JIT */