2010-02-10 Miguel de Icaza <miguel@novell.com>
[mono.git] / mono / mini / mini-llvm.c
index 64aa1d132dc0c5bb755100a3553ce4df7cc95af7..ec83b7a13f95b699cd1f0268c3e9c3eb6ddfa845 100644 (file)
@@ -8,8 +8,12 @@
 #include <mono/metadata/debug-helpers.h>
 #include <mono/metadata/mempool-internals.h>
 
+#ifndef __STDC_LIMIT_MACROS
 #define __STDC_LIMIT_MACROS
+#endif
+#ifndef __STDC_CONSTANT_MACROS
 #define __STDC_CONSTANT_MACROS
+#endif
 
 #include "llvm-c/Core.h"
 #include "llvm-c/ExecutionEngine.h"
   */
 typedef struct {
        LLVMModuleRef module;
-       LLVMValueRef throw, throw_corlib_exception;     
+       LLVMValueRef throw, throw_corlib_exception;
        GHashTable *llvm_types;
        LLVMValueRef got_var;
        const char *got_symbol;
        GHashTable *plt_entries;
 } MonoLLVMModule;
 
+/*
+ * Information associated by the backend with mono basic blocks.
+ */
+typedef struct {
+       LLVMBasicBlockRef bblock, end_bblock;
+       LLVMValueRef finally_ind;
+       gboolean added, invoke_target;
+       /* 
+        * If this bblock is the start of a finally clause, this is a list of bblocks it
+        * needs to branch to in ENDFINALLY.
+        */
+       GSList *call_handler_return_bbs;
+       LLVMValueRef endfinally_switch;
+       GSList *phi_nodes;
+} BBInfo;
+
 /*
  * Structure containing emit state
  */
@@ -43,7 +63,7 @@ typedef struct {
        LLVMValueRef lmethod;
        MonoLLVMModule *lmodule;
        LLVMModuleRef module;
-       LLVMBasicBlockRef *bblocks, *end_bblocks;
+       BBInfo *bblocks;
        int sindex, default_index, ex_index;
        LLVMBuilderRef builder;
        LLVMValueRef *values, *addresses;
@@ -51,6 +71,9 @@ typedef struct {
        LLVMCallInfo *linfo;
        MonoMethodSignature *sig;
        GSList *builders;
+       GHashTable *region_to_handler;
+       LLVMBuilderRef alloca_builder;
+       LLVMValueRef last_alloca;
 
        char temp_name [32];
 } EmitContext;
@@ -144,6 +167,9 @@ static LLVMExecutionEngineRef ee;
 static guint32 current_cfg_tls_id;
 
 static MonoLLVMModule jit_module, aot_module;
+static gboolean jit_module_inited;
+
+static void init_jit_module (void);
 
 /*
  * IntPtrType:
@@ -441,6 +467,7 @@ op_to_llvm_type (int opcode)
        case OP_IMUL_OVF_UN:
                return LLVMInt32Type ();
        case OP_LADD_OVF:
+       case OP_LADD_OVF_UN:
        case OP_LSUB_OVF:
        case OP_LSUB_OVF_UN:
        case OP_LMUL_OVF:
@@ -561,6 +588,38 @@ ovf_op_to_intrins (int opcode)
        }
 }
 
+static const char*
+simd_op_to_intrins (int opcode)
+{
+       switch (opcode) {
+#if defined(TARGET_X86) || defined(TARGET_AMD64)
+       case OP_MINPD:
+               return "llvm.x86.sse2.min.pd";
+       case OP_MINPS:
+               return "llvm.x86.sse2.min.ps";
+       case OP_PMIND_UN:
+               return "llvm.x86.sse41.pminud";
+       case OP_PMINW_UN:
+               return "llvm.x86.sse41.pminuw";
+       case OP_PMINB_UN:
+               return "llvm.x86.sse41.pminub";
+       case OP_MAXPD:
+               return "llvm.x86.sse2.max.pd";
+       case OP_MAXPS:
+               return "llvm.x86.sse2.max.ps";
+       case OP_PMAXD_UN:
+               return "llvm.x86.sse41.pmaxud";
+       case OP_PMAXW_UN:
+               return "llvm.x86.sse41.pmaxuw";
+       case OP_PMAXB_UN:
+               return "llvm.x86.sse41.pmaxub";
+#endif
+       default:
+               g_assert_not_reached ();
+               return NULL;
+       }
+}
+
 /*
  * get_bb:
  *
@@ -571,14 +630,14 @@ get_bb (EmitContext *ctx, MonoBasicBlock *bb)
 {
        char bb_name [128];
 
-       if (ctx->bblocks [bb->block_num] == NULL) {
+       if (ctx->bblocks [bb->block_num].bblock == NULL) {
                sprintf (bb_name, "BB%d", bb->block_num);
 
-               ctx->bblocks [bb->block_num] = LLVMAppendBasicBlock (ctx->lmethod, bb_name);
-               ctx->end_bblocks [bb->block_num] = ctx->bblocks [bb->block_num];
+               ctx->bblocks [bb->block_num].bblock = LLVMAppendBasicBlock (ctx->lmethod, bb_name);
+               ctx->bblocks [bb->block_num].end_bblock = ctx->bblocks [bb->block_num].bblock;
        }
 
-       return ctx->bblocks [bb->block_num];
+       return ctx->bblocks [bb->block_num].bblock;
 }
 
 /* 
@@ -592,7 +651,16 @@ static LLVMBasicBlockRef
 get_end_bb (EmitContext *ctx, MonoBasicBlock *bb)
 {
        get_bb (ctx, bb);
-       return ctx->end_bblocks [bb->block_num];
+       return ctx->bblocks [bb->block_num].end_bblock;
+}
+
+static LLVMBasicBlockRef
+gen_bb (EmitContext *ctx, const char *prefix)
+{
+       char bb_name [128];
+
+       sprintf (bb_name, "%s%d", prefix, ++ ctx->ex_index);
+       return LLVMAppendBasicBlock (ctx->lmethod, bb_name);
 }
 
 /*
@@ -703,7 +771,7 @@ emit_volatile_load (EmitContext *ctx, int vreg)
 }
 
 /*
- * emit_volatile_store_full:
+ * emit_volatile_store:
  *
  *   If VREG is volatile, emit a store from its value to its address.
  */
@@ -880,6 +948,8 @@ get_plt_entry (EmitContext *ctx, LLVMTypeRef llvm_sig, MonoJumpInfoType type, gc
        if (!callee) {
                callee = LLVMAddFunction (ctx->module, callee_name, llvm_sig);
 
+               LLVMSetVisibility (callee, LLVMHiddenVisibility);
+
                g_hash_table_insert (ctx->lmodule->plt_entries, (char*)callee_name, callee);
        }
 
@@ -891,6 +961,61 @@ emit_cond_throw_pos (EmitContext *ctx)
 {
 }
 
+/*
+ * emit_call:
+ *
+ *   Emit an LLVM call or invoke instruction depending on whenever the call is inside
+ * a try region.
+ */
+static LLVMValueRef
+emit_call (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref, LLVMValueRef callee, LLVMValueRef *args, int pindex)
+{
+       MonoCompile *cfg = ctx->cfg;
+       LLVMValueRef lcall;
+       LLVMBuilderRef builder = *builder_ref;
+
+       // FIXME: Nested clauses
+       if (bb->region != -1 && MONO_BBLOCK_IS_IN_REGION (bb, MONO_REGION_TRY)) {
+               MonoMethodHeader *header = mono_method_get_header (cfg->method);
+               // FIXME: Add a macro for this
+               int clause_index = (bb->region >> 8) - 1;
+               MonoExceptionClause *ec = &header->clauses [clause_index];
+               MonoBasicBlock *tblock;
+               LLVMBasicBlockRef ex_bb, noex_bb;
+
+               /*
+                * Have to use an invoke instead of a call, branching to the
+                * handler bblock of the clause containing this bblock.
+                */
+
+               g_assert (ec->flags == MONO_EXCEPTION_CLAUSE_NONE || ec->flags == MONO_EXCEPTION_CLAUSE_FINALLY);
+
+               tblock = cfg->cil_offset_to_bb [ec->handler_offset];
+               g_assert (tblock);
+
+               ctx->bblocks [tblock->block_num].invoke_target = TRUE;
+
+               ex_bb = get_bb (ctx, tblock);
+
+               noex_bb = gen_bb (ctx, "NOEX_BB");
+
+               /* Use an invoke */
+               lcall = LLVMBuildInvoke (builder, callee, args, pindex, noex_bb, ex_bb, "");
+
+               builder = ctx->builder = create_builder (ctx);
+               LLVMPositionBuilderAtEnd (ctx->builder, noex_bb);
+
+               ctx->bblocks [bb->block_num].end_bblock = noex_bb;
+       } else {
+               lcall = LLVMBuildCall (builder, callee, args, pindex, "");
+               ctx->builder = builder;
+       }
+
+       *builder_ref = ctx->builder;
+
+       return lcall;
+}
+
 /*
  * emit_cond_system_exception:
  *
@@ -899,25 +1024,16 @@ emit_cond_throw_pos (EmitContext *ctx)
 static void
 emit_cond_system_exception (EmitContext *ctx, MonoBasicBlock *bb, const char *exc_type, LLVMValueRef cmp)
 {
-       char bb_name [128];
        LLVMBasicBlockRef ex_bb, noex_bb;
        LLVMBuilderRef builder;
        MonoClass *exc_class;
        LLVMValueRef args [2];
 
-       sprintf (bb_name, "EX_BB%d", ctx->ex_index);
-       ex_bb = LLVMAppendBasicBlock (ctx->lmethod, bb_name);
-
-       sprintf (bb_name, "NOEX_BB%d", ctx->ex_index);
-       noex_bb = LLVMAppendBasicBlock (ctx->lmethod, bb_name);
+       ex_bb = gen_bb (ctx, "EX_BB");
+       noex_bb = gen_bb (ctx, "NOEX_BB");
 
        LLVMBuildCondBr (ctx->builder, cmp, ex_bb, noex_bb);
 
-       ctx->builder = create_builder (ctx);
-       LLVMPositionBuilderAtEnd (ctx->builder, noex_bb);
-
-       ctx->end_bblocks [bb->block_num] = noex_bb;
-
        exc_class = mono_class_from_name (mono_defaults.corlib, "System", exc_type);
        g_assert (exc_class);
 
@@ -939,25 +1055,42 @@ emit_cond_system_exception (EmitContext *ctx, MonoBasicBlock *bb, const char *ex
                        callee = get_plt_entry (ctx, sig, MONO_PATCH_INFO_INTERNAL_METHOD, "mono_arch_throw_corlib_exception");
                } else {
                        callee = LLVMAddFunction (ctx->module, "throw_corlib_exception", sig_to_llvm_sig (ctx, throw_sig, NULL));
+
+#ifdef TARGET_X86 
+                       /* 
+                        * LLVM generated code doesn't push the arguments, so we need another
+                        * throw trampoline.
+                        */
+                       LLVMAddGlobalMapping (ee, callee, resolve_patch (ctx->cfg, MONO_PATCH_INFO_INTERNAL_METHOD, "mono_arch_llvm_throw_corlib_exception"));
+#else
                        LLVMAddGlobalMapping (ee, callee, resolve_patch (ctx->cfg, MONO_PATCH_INFO_INTERNAL_METHOD, "mono_arch_throw_corlib_exception"));
+#endif
                }
 
                mono_memory_barrier ();
                ctx->lmodule->throw_corlib_exception = callee;
        }
 
+#ifdef TARGET_X86
+       args [0] = LLVMConstInt (LLVMInt32Type (), exc_class->type_token - MONO_TOKEN_TYPE_DEF, FALSE);
+#else
        args [0] = LLVMConstInt (LLVMInt32Type (), exc_class->type_token, FALSE);
+#endif
        /*
         * FIXME: The offset is 0, this is not a problem for exception handling
         * in general, because we don't llvm compile methods with handlers, its only
         * a problem for line numbers in stack traces.
         */
        args [1] = LLVMConstInt (LLVMInt32Type (), 0, FALSE);
-       LLVMBuildCall (builder, ctx->lmodule->throw_corlib_exception, args, 2, "");
+       emit_call (ctx, bb, &builder, ctx->lmodule->throw_corlib_exception, args, 2);
 
        LLVMBuildUnreachable (builder);
 
+       ctx->builder = create_builder (ctx);
+       LLVMPositionBuilderAtEnd (ctx->builder, noex_bb);
+
+       ctx->bblocks [bb->block_num].end_bblock = noex_bb;
+
        ctx->ex_index ++;
 }
 
@@ -1022,6 +1155,10 @@ emit_vtype_to_reg (EmitContext *ctx, LLVMBuilderRef builder, MonoType *t, LLVMVa
 
        size = get_vtype_size (t);
 
+       if (MONO_CLASS_IS_SIMD (ctx->cfg, mono_class_from_mono_type (t))) {
+               address = LLVMBuildBitCast (ctx->builder, address, LLVMPointerType (LLVMInt8Type (), 0), "");
+       }
+
        for (j = 0; j < 2; ++j) {
                LLVMValueRef index [2], addr;
                int partsize = size > sizeof (gpointer) ? sizeof (gpointer) : size;
@@ -1029,9 +1166,14 @@ emit_vtype_to_reg (EmitContext *ctx, LLVMBuilderRef builder, MonoType *t, LLVMVa
                if (ainfo->pair_storage [j] == LLVMArgNone)
                        continue;
 
-               index [0] = LLVMConstInt (LLVMInt32Type (), 0, FALSE);
-               index [1] = LLVMConstInt (LLVMInt32Type (), j * sizeof (gpointer), FALSE);                              
-               addr = LLVMBuildGEP (builder, address, index, 2, "");
+               if (MONO_CLASS_IS_SIMD (ctx->cfg, mono_class_from_mono_type (t))) {
+                       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, "");
+               }
                switch (ainfo->pair_storage [j]) {
                case LLVMArgInIReg:
                        regs [pindex ++] = convert (ctx, LLVMBuildLoad (builder, LLVMBuildBitCast (ctx->builder, addr, LLVMPointerType (LLVMIntType (partsize * 8), 0), ""), ""), IntPtrType ());
@@ -1047,6 +1189,48 @@ emit_vtype_to_reg (EmitContext *ctx, LLVMBuilderRef builder, MonoType *t, LLVMVa
        *nregs = pindex;
 }
 
+static LLVMValueRef
+build_alloca (EmitContext *ctx, MonoType *t)
+{
+       MonoClass *k = mono_class_from_mono_type (t);
+       int align;
+
+       if (MONO_CLASS_IS_SIMD (ctx->cfg, k))
+               align = 16;
+       else
+               align = mono_class_min_align (k);
+
+       /* Sometimes align is not a power of 2 */
+       while (mono_is_power_of_two (align) == -1)
+               align ++;
+
+       /*
+        * Have to place all alloca's at the end of the entry bb, since otherwise they would
+        * get executed every time control reaches them.
+        */
+       LLVMPositionBuilder (ctx->alloca_builder, get_bb (ctx, ctx->cfg->bb_entry), ctx->last_alloca);
+
+       ctx->last_alloca = mono_llvm_build_alloca (ctx->alloca_builder, type_to_llvm_type (ctx, t), NULL, align, "");
+       return ctx->last_alloca;
+}
+
+/*
+ * Put the global into the 'llvm.used' array to prevent it from being optimized away.
+ */
+static void
+mark_as_used (LLVMModuleRef module, LLVMValueRef global)
+{
+       LLVMTypeRef used_type;
+       LLVMValueRef used, used_elem;
+               
+       used_type = LLVMArrayType (LLVMPointerType (LLVMInt8Type (), 0), 1);
+       used = LLVMAddGlobal (module, used_type, "llvm.used");
+       used_elem = LLVMConstBitCast (global, LLVMPointerType (LLVMInt8Type (), 0));
+       LLVMSetInitializer (used, LLVMConstArray (LLVMPointerType (LLVMInt8Type (), 0), &used_elem, 1));
+       LLVMSetLinkage (used, LLVMAppendingLinkage);
+       LLVMSetSection (used, "llvm.metadata");
+}
+
 /*
  * emit_entry_bb:
  *
@@ -1059,6 +1243,9 @@ emit_entry_bb (EmitContext *ctx, LLVMBuilderRef builder, int *pindexes)
        MonoCompile *cfg = ctx->cfg;
        MonoMethodSignature *sig = ctx->sig;
        LLVMCallInfo *linfo = ctx->linfo;
+       MonoBasicBlock *bb;
+
+       ctx->alloca_builder = create_builder (ctx);
 
        /*
         * Handle indirect/volatile variables by allocating memory for them
@@ -1073,7 +1260,7 @@ emit_entry_bb (EmitContext *ctx, LLVMBuilderRef builder, int *pindexes)
                        CHECK_FAILURE (ctx);
                        /* Could be already created by an OP_VPHI */
                        if (!ctx->addresses [var->dreg])
-                               ctx->addresses [var->dreg] = LLVMBuildAlloca (builder, vtype, "");
+                               ctx->addresses [var->dreg] = build_alloca (ctx, var->inst_vtype);
                        ctx->vreg_cli_types [var->dreg] = var->inst_vtype;
                }
        }
@@ -1096,9 +1283,14 @@ emit_entry_bb (EmitContext *ctx, LLVMBuilderRef builder, int *pindexes)
                        else
                                regs [1] = NULL;
 
-                       ctx->addresses [reg] = LLVMBuildAlloca (builder, type_to_llvm_type (ctx, &(mono_class_from_mono_type (sig->params [i])->byval_arg)), "");
+                       ctx->addresses [reg] = build_alloca (ctx, sig->params [i]);
 
                        emit_reg_to_vtype (ctx, builder, sig->params [i], ctx->addresses [reg], ainfo, regs);
+
+                       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 == LLVMArgVtypeByVal) {
                        ctx->addresses [reg] = LLVMGetParam (ctx->lmethod, pindexes [i]);
                } else {
@@ -1106,14 +1298,44 @@ emit_entry_bb (EmitContext *ctx, LLVMBuilderRef builder, int *pindexes)
                }
        }
 
+       if (cfg->vret_addr)
+               emit_volatile_store (ctx, cfg->vret_addr->dreg);
+       if (sig->hasthis)
+               emit_volatile_store (ctx, cfg->args [0]->dreg);
        for (i = 0; i < sig->param_count; ++i)
                if (!MONO_TYPE_ISSTRUCT (sig->params [i]))
                        emit_volatile_store (ctx, cfg->args [i + sig->hasthis]->dreg);
 
+       /*
+        * For finally clauses, create an indicator variable telling OP_ENDFINALLY whenever
+        * it needs to continue normally, or return back to the exception handling system.
+        */
+       for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
+               if (bb->region != -1 && (bb->flags & BB_EXCEPTION_HANDLER))
+                       g_hash_table_insert (ctx->region_to_handler, GUINT_TO_POINTER (mono_get_block_region_notry (cfg, bb->region)), bb);
+               if (bb->region != -1 && (bb->flags & BB_EXCEPTION_HANDLER) && bb->in_scount == 0) {
+                       LLVMValueRef val = LLVMBuildAlloca (builder, LLVMInt32Type (), "");
+                       LLVMBuildStore (builder, LLVMConstInt (LLVMInt32Type (), 0, FALSE), val);
+
+                       ctx->bblocks [bb->block_num].finally_ind = val;
+               }
+       }
+
  FAILURE:
        ;
 }
 
+/* Have to export this for AOT */
+void
+mono_personality (void);
+       
+void
+mono_personality (void)
+{
+       /* Not used */
+       g_assert_not_reached ();
+}
+
 /*
  * mono_llvm_emit_method:
  *
@@ -1133,7 +1355,6 @@ mono_llvm_emit_method (MonoCompile *cfg)
        MonoType **vreg_cli_types;
        int i, max_block_num, pindex, bb_index;
        int *pindexes = NULL;
-       GHashTable *phi_nodes;
        gboolean last = FALSE;
        GPtrArray *phi_values;
        LLVMCallInfo *linfo;
@@ -1141,6 +1362,10 @@ mono_llvm_emit_method (MonoCompile *cfg)
        LLVMModuleRef module;
        gboolean *is_dead;
        gboolean *unreachable;
+       BBInfo *bblocks;
+       GPtrArray *bblock_list;
+       MonoMethodHeader *header;
+       MonoExceptionClause *clause;
 
        /* The code below might acquire the loader lock, so use it for global locking */
        mono_loader_lock ();
@@ -1163,7 +1388,6 @@ mono_llvm_emit_method (MonoCompile *cfg)
        addresses = g_new0 (LLVMValueRef, cfg->next_vreg);
        vreg_types = g_new0 (LLVMTypeRef, cfg->next_vreg);
        vreg_cli_types = g_new0 (MonoType*, cfg->next_vreg);
-       phi_nodes = g_hash_table_new (NULL, NULL);
        phi_values = g_ptr_array_new ();
        /* 
         * This signals whenever the vreg was defined by a phi node with no input vars
@@ -1173,15 +1397,19 @@ mono_llvm_emit_method (MonoCompile *cfg)
        /* Whenever the bblock is unreachable */
        unreachable = g_new0 (gboolean, cfg->max_block_num);
 
+       bblock_list = g_ptr_array_new ();
+
        ctx->values = values;
        ctx->addresses = addresses;
        ctx->vreg_cli_types = vreg_cli_types;
+       ctx->region_to_handler = g_hash_table_new (NULL, NULL);
  
        if (cfg->compile_aot) {
                ctx->lmodule = &aot_module;
                method_name = mono_aot_get_method_name (cfg);
                debug_name = mono_aot_get_method_debug_name (cfg);
        } else {
+               init_jit_module ();
                ctx->lmodule = &jit_module;
                method_name = mono_method_full_name (cfg->method, TRUE);
                debug_name = NULL;
@@ -1226,6 +1454,13 @@ mono_llvm_emit_method (MonoCompile *cfg)
        if (sig->pinvoke)
                LLVM_FAILURE (ctx, "pinvoke signature");
 
+       header = mono_method_get_header (cfg->method);
+       for (i = 0; i < header->num_clauses; ++i) {
+               clause = &header->clauses [i];
+               if (clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_NONE)
+                       LLVM_FAILURE (ctx, "non-finally/catch clause.");
+       }
+
        /* 
         * This maps parameter indexes in the original signature to the indexes in
         * the LLVM signature.
@@ -1259,8 +1494,7 @@ mono_llvm_emit_method (MonoCompile *cfg)
        max_block_num = 0;
        for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
                max_block_num = MAX (max_block_num, bb->block_num);
-       ctx->bblocks = g_new0 (LLVMBasicBlockRef, max_block_num + 1);
-       ctx->end_bblocks = g_new0 (LLVMBasicBlockRef, max_block_num + 1);
+       ctx->bblocks = bblocks = g_new0 (BBInfo, max_block_num + 1);
 
        /* Add branches between non-consecutive bblocks */
        for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
@@ -1332,12 +1566,27 @@ mono_llvm_emit_method (MonoCompile *cfg)
                }
        }
 
-       /*
-        * Second pass: generate code.
+       /* 
+        * Create an ordering for bblocks, use the depth first order first, then
+        * put the exception handling bblocks last.
         */
        for (bb_index = 0; bb_index < cfg->num_bblocks; ++bb_index) {
+               bb = cfg->bblocks [bb_index];
+               if (!(bb->region != -1 && !MONO_BBLOCK_IS_IN_REGION (bb, MONO_REGION_TRY))) {
+                       g_ptr_array_add (bblock_list, bb);
+                       bblocks [bb->block_num].added = TRUE;
+               }
+       }
+
+       for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
+               if (!bblocks [bb->block_num].added)
+                       g_ptr_array_add (bblock_list, bb);
+       }
 
-               //for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
+       /*
+        * Second pass: generate code.
+        */
+       for (bb_index = 0; bb_index < bblock_list->len; ++bb_index) {
                MonoInst *ins;
                LLVMBasicBlockRef cbb;
                LLVMBuilderRef builder;
@@ -1345,7 +1594,7 @@ mono_llvm_emit_method (MonoCompile *cfg)
                LLVMValueRef v;
                LLVMValueRef lhs, rhs;
 
-               bb = cfg->bblocks [bb_index];
+               bb = g_ptr_array_index (bblock_list, bb_index);
 
                if (!(bb == cfg->bb_entry || bb->in_count > 0))
                        continue;
@@ -1359,6 +1608,91 @@ mono_llvm_emit_method (MonoCompile *cfg)
                        emit_entry_bb (ctx, builder, pindexes);
                CHECK_FAILURE (ctx);
 
+               if (bb->flags & BB_EXCEPTION_HANDLER) {
+                       LLVMTypeRef i8ptr;
+                       LLVMValueRef eh_selector, eh_exception, personality, args [4];
+                       MonoInst *exvar;
+                       static gint32 mapping_inited;
+                       static int ti_generator;
+                       char ti_name [128];
+                       MonoClass **ti;
+                       LLVMValueRef type_info;
+                       int clause_index;
+
+                       if (!bblocks [bb->block_num].invoke_target) {
+                               /*
+                                * LLVM asserts if llvm.eh.selector is called from a bblock which
+                                * doesn't have an invoke pointing at it.
+                                */
+                               LLVM_FAILURE (ctx, "handler without invokes");
+                       }
+
+                       eh_selector = LLVMGetNamedFunction (module, "llvm.eh.selector");
+
+                       if (cfg->compile_aot) {
+                               /* Use a dummy personality function */
+                               personality = LLVMGetNamedFunction (module, "mono_aot_personality");
+                               g_assert (personality);
+                       } else {
+                               personality = LLVMGetNamedFunction (module, "mono_personality");
+                               if (InterlockedCompareExchange (&mapping_inited, 1, 0) == 0)
+                                       LLVMAddGlobalMapping (ee, personality, mono_personality);
+                       }
+
+                       i8ptr = LLVMPointerType (LLVMInt8Type (), 0);
+
+                       clause_index = (mono_get_block_region_notry (cfg, bb->region) >> 8) - 1;
+
+                       /*
+                        * Create the type info
+                        */
+                       sprintf (ti_name, "type_info_%d", ti_generator);
+                       ti_generator ++;
+
+                       if (cfg->compile_aot) {
+                               /* decode_eh_frame () in aot-runtime.c will decode this */
+                               type_info = LLVMAddGlobal (module, LLVMInt32Type (), ti_name);
+                               LLVMSetInitializer (type_info, LLVMConstInt (LLVMInt32Type (), clause_index, FALSE));
+
+                               LLVMSetLinkage (type_info, LLVMPrivateLinkage);
+                               LLVMSetVisibility (type_info, LLVMHiddenVisibility);
+
+                               /* 
+                                * FIXME: llc currently generates incorrect data in the LSDA:
+                                *      .byte   0x9B                                        # @TType format (indirect pcrel sdata4)
+                                * and later:
+                                * .quad        type_info_1                                 # TypeInfo
+                                */
+                               LLVM_FAILURE (ctx, "aot+clauses");
+                       } else {
+                               /* exception_cb will decode this */
+                               ti = g_malloc (sizeof (MonoExceptionClause));
+                               memcpy (ti, &mono_method_get_header (cfg->method)->clauses [clause_index], sizeof (MonoExceptionClause));
+
+                               type_info = LLVMAddGlobal (module, i8ptr, ti_name);
+
+                               LLVMAddGlobalMapping (ee, type_info, ti);
+                       }
+
+                       args [0] = LLVMConstNull (i8ptr);
+                       args [1] = LLVMConstBitCast (personality, i8ptr);
+                       args [2] = type_info;
+                       LLVMBuildCall (builder, eh_selector, args, 3, "");
+
+                       /* Store the exception into the exvar */
+                       if (bb->in_scount == 1) {
+                               g_assert (bb->in_scount == 1);
+                               exvar = bb->in_stack [0];
+
+                               eh_exception = LLVMGetNamedFunction (module, "llvm.eh.exception");
+
+                               // FIXME: This is shared with filter clauses ?
+                               g_assert (!values [exvar->dreg]);
+                               values [exvar->dreg] = LLVMBuildCall (builder, eh_exception, NULL, 0, "");
+                               emit_volatile_store (ctx, exvar->dreg);
+                       }
+               }
+
                has_terminator = FALSE;
                for (ins = bb->code; ins; ins = ins->next) {
                        const char *spec = LLVM_INS_INFO (ins->opcode);
@@ -1482,6 +1816,11 @@ mono_llvm_emit_method (MonoCompile *cfg)
                                        break;
                                }
 
+                               if (linfo->ret.storage == LLVMArgVtypeRetAddr) {
+                                       LLVMBuildRetVoid (builder);
+                                       break;
+                               }
+
                                if (!lhs || is_dead [ins->sreg1]) {
                                        /* 
                                         * The method did not set its return value, probably because it
@@ -1682,14 +2021,12 @@ mono_llvm_emit_method (MonoCompile *cfg)
 
                                        /* Remember for later */
                                        for (j = 0; j < count; ++j) {
-                                               GSList *node_list = g_hash_table_lookup (phi_nodes, GUINT_TO_POINTER (bb->in_bb [i]));
                                                PhiNode *node = mono_mempool_alloc0 (ctx->mempool, sizeof (PhiNode));
                                                node->bb = bb;
                                                node->phi = ins;
                                                node->in_bb = bb->in_bb [i];
                                                node->sreg = sreg1;
-                                               node_list = g_slist_prepend_mempool (ctx->mempool, node_list, node);
-                                               g_hash_table_insert (phi_nodes, GUINT_TO_POINTER (bb->in_bb [i]), node_list);
+                                               bblocks [bb->in_bb [i]->block_num].phi_nodes = g_slist_prepend_mempool (ctx->mempool, bblocks [bb->in_bb [i]->block_num].phi_nodes, node);
                                        }
                                }
                                break;
@@ -2090,9 +2427,10 @@ mono_llvm_emit_method (MonoCompile *cfg)
                        case OP_LOADU4_MEM:
                        case OP_LOAD_MEM: {
                                int size = 8;
-                               LLVMValueRef index;
+                               LLVMValueRef index, addr;
                                LLVMTypeRef t;
                                gboolean sext = FALSE, zext = FALSE;
+                               gboolean is_volatile = (ins->flags & MONO_INST_FAULT);
 
                                t = load_store_to_llvm_type (ins->opcode, &size, &sext, &zext);
 
@@ -2100,20 +2438,27 @@ mono_llvm_emit_method (MonoCompile *cfg)
                                        dname = (char*)"";
 
                                /* 
-                                * We emit volatile loads because otherwise LLVM will
-                                * generate invalid code when encountering a load from a
+                                * We emit volatile loads for loads which can fault, because otherwise
+                                * LLVM will generate invalid code when encountering a load from a
                                 * NULL address.
-                                * FIXME: Avoid this somehow.
                                 */
-                               g_assert (ins->inst_offset % size == 0);
                                if ((ins->opcode == OP_LOADI8_MEM) || (ins->opcode == OP_LOAD_MEM) || (ins->opcode == OP_LOADI4_MEM) || (ins->opcode == OP_LOADU4_MEM) || (ins->opcode == OP_LOADU1_MEM) || (ins->opcode == OP_LOADU2_MEM)) {
-                                       values [ins->dreg] = mono_llvm_build_volatile_load (builder, convert (ctx, LLVMConstInt (IntPtrType (), ins->inst_imm, FALSE), LLVMPointerType (t, 0)), dname);
+                                       addr = LLVMConstInt (IntPtrType (), ins->inst_imm, FALSE);
                                } else if (ins->inst_offset == 0) {
-                                       values [ins->dreg] = mono_llvm_build_volatile_load (builder, convert (ctx, values [ins->inst_basereg], LLVMPointerType (t, 0)), dname);
+                                       addr = values [ins->inst_basereg];
+                               } else if (ins->inst_offset % size != 0) {
+                                       /* Unaligned load */
+                                       index = LLVMConstInt (LLVMInt32Type (), ins->inst_offset, FALSE);
+                                       addr = LLVMBuildGEP (builder, convert (ctx, values [ins->inst_basereg], LLVMPointerType (LLVMInt8Type (), 0)), &index, 1, "");
                                } else {
                                        index = LLVMConstInt (LLVMInt32Type (), ins->inst_offset / size, FALSE);                                
-                                       values [ins->dreg] = mono_llvm_build_volatile_load (builder, LLVMBuildGEP (builder, convert (ctx, values [ins->inst_basereg], LLVMPointerType (t, 0)), &index, 1, ""), dname);
+                                       addr = LLVMBuildGEP (builder, convert (ctx, values [ins->inst_basereg], LLVMPointerType (t, 0)), &index, 1, "");
                                }
+
+                               addr = convert (ctx, addr, LLVMPointerType (t, 0));
+
+                               values [ins->dreg] = mono_llvm_build_load (builder, addr, dname, is_volatile);
+
                                if (sext)
                                        values [ins->dreg] = LLVMBuildSExt (builder, values [ins->dreg], LLVMInt32Type (), dname);
                                else if (zext)
@@ -2131,15 +2476,21 @@ mono_llvm_emit_method (MonoCompile *cfg)
                        case OP_STORER8_MEMBASE_REG:
                        case OP_STORE_MEMBASE_REG: {
                                int size = 8;
-                               LLVMValueRef index;
+                               LLVMValueRef index, addr;
                                LLVMTypeRef t;
                                gboolean sext = FALSE, zext = FALSE;
 
                                t = load_store_to_llvm_type (ins->opcode, &size, &sext, &zext);
 
-                               g_assert (ins->inst_offset % size == 0);
-                               index = LLVMConstInt (LLVMInt32Type (), ins->inst_offset / size, FALSE);                                
-                               LLVMBuildStore (builder, convert (ctx, values [ins->sreg1], t), LLVMBuildGEP (builder, convert (ctx, values [ins->inst_destbasereg], LLVMPointerType (t, 0)), &index, 1, ""));
+                               if (ins->inst_offset % size != 0) {
+                                       /* Unaligned store */
+                                       index = LLVMConstInt (LLVMInt32Type (), ins->inst_offset, FALSE);
+                                       addr = LLVMBuildGEP (builder, convert (ctx, values [ins->inst_destbasereg], LLVMPointerType (LLVMInt8Type (), 0)), &index, 1, "");
+                               } else {
+                                       index = LLVMConstInt (LLVMInt32Type (), ins->inst_offset / size, FALSE);                                
+                                       addr = LLVMBuildGEP (builder, convert (ctx, values [ins->inst_destbasereg], LLVMPointerType (t, 0)), &index, 1, "");
+                               }
+                               LLVMBuildStore (builder, convert (ctx, values [ins->sreg1], t), convert (ctx, addr, LLVMPointerType (t, 0)));
                                break;
                        }
 
@@ -2149,20 +2500,26 @@ mono_llvm_emit_method (MonoCompile *cfg)
                        case OP_STOREI8_MEMBASE_IMM:
                        case OP_STORE_MEMBASE_IMM: {
                                int size = 8;
-                               LLVMValueRef index;
+                               LLVMValueRef index, addr;
                                LLVMTypeRef t;
                                gboolean sext = FALSE, zext = FALSE;
 
                                t = load_store_to_llvm_type (ins->opcode, &size, &sext, &zext);
 
-                               g_assert (ins->inst_offset % size == 0);
-                               index = LLVMConstInt (LLVMInt32Type (), ins->inst_offset / size, FALSE);                                
-                               LLVMBuildStore (builder, convert (ctx, LLVMConstInt (LLVMInt32Type (), ins->inst_imm, FALSE), t), LLVMBuildGEP (builder, convert (ctx, values [ins->inst_destbasereg], LLVMPointerType (t, 0)), &index, 1, ""));
+                               if (ins->inst_offset % size != 0) {
+                                       /* Unaligned store */
+                                       index = LLVMConstInt (LLVMInt32Type (), ins->inst_offset, FALSE);
+                                       addr = LLVMBuildGEP (builder, convert (ctx, values [ins->inst_destbasereg], LLVMPointerType (LLVMInt8Type (), 0)), &index, 1, "");
+                               } else {
+                                       index = LLVMConstInt (LLVMInt32Type (), ins->inst_offset / size, FALSE);                                
+                                       addr = LLVMBuildGEP (builder, convert (ctx, values [ins->inst_destbasereg], LLVMPointerType (t, 0)), &index, 1, "");
+                               }
+                               LLVMBuildStore (builder, convert (ctx, LLVMConstInt (LLVMInt32Type (), ins->inst_imm, FALSE), t), addr);
                                break;
                        }
 
                        case OP_CHECK_THIS:
-                               mono_llvm_build_volatile_load (builder, convert (ctx, values [ins->sreg1], LLVMPointerType (IntPtrType (), 0)), "");
+                               mono_llvm_build_load (builder, convert (ctx, values [ins->sreg1], LLVMPointerType (IntPtrType (), 0)), "", TRUE);
                                break;
                        case OP_OUTARG_VTRETADDR:
                                break;
@@ -2201,14 +2558,10 @@ mono_llvm_emit_method (MonoCompile *cfg)
                                llvm_sig = sig_to_llvm_sig (ctx, sig, cinfo);
                                CHECK_FAILURE (ctx);
 
-                               if (call->rgctx_reg) {
-                                       LLVM_FAILURE (ctx, "rgctx 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);
                                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);
 
-                               pindexes = mono_mempool_alloc0 (cfg->mempool, sig->param_count + 2);
+                               pindexes = mono_mempool_alloc0 (cfg->mempool, (sig->param_count + 2) * sizeof (guint32));
 
                                /* FIXME: Avoid creating duplicate methods */
 
@@ -2271,9 +2624,14 @@ mono_llvm_emit_method (MonoCompile *cfg)
                                                        if (cfg->abs_patches) {
                                                                MonoJumpInfo *abs_ji = g_hash_table_lookup (cfg->abs_patches, call->fptr);
                                                                if (abs_ji) {
+                                                                       /*
+                                                                        * The monitor entry/exit trampolines might have
+                                                                        * 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)
-                                                                               /* FIXME: These have their own calling convention */
                                                                                LLVM_FAILURE (ctx, "monitor enter/exit");
+#endif
                                                                        target = mono_resolve_patch_target (cfg->method, cfg->domain, NULL, abs_ji, FALSE);
                                                                        LLVMAddGlobalMapping (ee, callee, target);
                                                                }
@@ -2331,7 +2689,7 @@ mono_llvm_emit_method (MonoCompile *cfg)
                                pindex = 0;
                                if (vretaddr) {
                                        if (!addresses [call->inst.dreg])
-                                               addresses [call->inst.dreg] = LLVMBuildAlloca (builder, type_to_llvm_type (ctx, &(mono_class_from_mono_type (sig->ret)->byval_arg)), "");
+                                               addresses [call->inst.dreg] = build_alloca (ctx, sig->ret);
                                        args [pindex ++] = LLVMBuildPtrToInt (builder, addresses [call->inst.dreg], IntPtrType (), "");
                                }
 
@@ -2380,7 +2738,8 @@ mono_llvm_emit_method (MonoCompile *cfg)
                                /*
                                 * Emit the call
                                 */
-                               lcall = LLVMBuildCall (builder, callee, args, pindex, "");
+
+                               lcall = emit_call (ctx, bb, &builder, callee, args, pindex);
 
                                /* Add byval attributes if needed */
                                for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
@@ -2398,7 +2757,7 @@ mono_llvm_emit_method (MonoCompile *cfg)
                                        LLVMValueRef regs [2];
 
                                        if (!addresses [ins->dreg])
-                                               addresses [ins->dreg] = LLVMBuildAlloca (builder, type_to_llvm_type (ctx, &(mono_class_from_mono_type (sig->ret)->byval_arg)), "");
+                                               addresses [ins->dreg] = build_alloca (ctx, sig->ret);
 
                                        regs [0] = LLVMBuildExtractValue (builder, lcall, 0, "");
                                        if (cinfo->ret.pair_storage [1] != LLVMArgNone)
@@ -2416,6 +2775,7 @@ mono_llvm_emit_method (MonoCompile *cfg)
                                guint32 got_offset;
                                LLVMValueRef indexes [2];
                                MonoJumpInfo *ji;
+                               LLVMValueRef got_entry_addr;
 
                                /* 
                                 * FIXME: Can't allocate from the cfg mempool since that is freed if
@@ -2435,31 +2795,27 @@ mono_llvm_emit_method (MonoCompile *cfg)
  
                                indexes [0] = LLVMConstInt (LLVMInt32Type (), 0, FALSE);
                                indexes [1] = LLVMConstInt (LLVMInt32Type (), (gssize)got_offset, FALSE);
-                               values [ins->dreg] = LLVMBuildLoad (builder, LLVMBuildGEP (builder, ctx->lmodule->got_var, indexes, 2, ""), dname);
-                               break;
-                       }
-                       case OP_THROW: {
-                               MonoMethodSignature *throw_sig;
-                               LLVMValueRef callee, arg;
+                               got_entry_addr = LLVMBuildGEP (builder, ctx->lmodule->got_var, indexes, 2, "");
 
-                               if (!ctx->lmodule->throw) {
-                                       throw_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
-                                       throw_sig->ret = &mono_defaults.void_class->byval_arg;
-                                       throw_sig->params [0] = &mono_defaults.object_class->byval_arg;
-                                       if (cfg->compile_aot) {
-                                               callee = get_plt_entry (ctx, sig_to_llvm_sig (ctx, throw_sig, NULL), MONO_PATCH_INFO_INTERNAL_METHOD, "mono_arch_throw_exception");
-                                       } else {
-                                               callee = LLVMAddFunction (module, "mono_arch_throw_exception", sig_to_llvm_sig (ctx, throw_sig, NULL));
-                                               LLVMAddGlobalMapping (ee, callee, resolve_patch (cfg, MONO_PATCH_INFO_INTERNAL_METHOD, "mono_arch_throw_exception"));
-                                       }
+                               // FIXME: This doesn't work right now, because it must be
+                               // paired with an invariant.end, and even then, its only in effect
+                               // inside its basic block
+#if 0
+                               {
+                                       LLVMValueRef args [3];
+                                       LLVMValueRef ptr, val;
 
-                                       mono_memory_barrier ();
-                                       ctx->lmodule->throw = callee;
+                                       ptr = LLVMBuildBitCast (builder, got_entry_addr, LLVMPointerType (LLVMInt8Type (), 0), "ptr");
+
+                                       args [0] = LLVMConstInt (LLVMInt64Type (), sizeof (gpointer), FALSE);
+                                       args [1] = ptr;
+                                       val = LLVMBuildCall (builder, LLVMGetNamedFunction (module, "llvm.invariant.start"), args, 2, "");
                                }
-                               arg = convert (ctx, values [ins->sreg1], type_to_llvm_type (ctx, &mono_defaults.object_class->byval_arg));
-                               LLVMBuildCall (builder, ctx->lmodule->throw, &arg, 1, "");
-                               break;
-                       }
+#endif
+
+                               values [ins->dreg] = LLVMBuildLoad (builder, got_entry_addr, dname);
+                               break;
+                       }
                        case OP_NOT_REACHED:
                                LLVMBuildUnreachable (builder);
                                has_terminator = TRUE;
@@ -2502,6 +2858,14 @@ mono_llvm_emit_method (MonoCompile *cfg)
                        }
                                */
 
+                       case OP_ABS: {
+                               LLVMValueRef args [1];
+
+                               args [0] = lhs;
+                               values [ins->dreg] = LLVMBuildCall (builder, LLVMGetNamedFunction (module, "fabs"), args, 1, dname);
+                               break;
+                       }
+
                        case OP_IMIN:
                        case OP_LMIN: {
                                LLVMValueRef v = LLVMBuildICmp (builder, LLVMIntSLE, lhs, rhs, "");
@@ -2635,6 +2999,7 @@ mono_llvm_emit_method (MonoCompile *cfg)
                        case OP_IMUL_OVF_UN:
 #if SIZEOF_VOID_P == 8
                        case OP_LADD_OVF:
+                       case OP_LADD_OVF_UN:
                        case OP_LSUB_OVF:
                        case OP_LSUB_OVF_UN:
                        case OP_LMUL_OVF:
@@ -2675,7 +3040,7 @@ mono_llvm_emit_method (MonoCompile *cfg)
                                }
 
                                if (!addresses [ins->dreg])
-                                       addresses [ins->dreg] = LLVMBuildAlloca (builder, type_to_llvm_type (ctx, &klass->byval_arg), "");
+                                       addresses [ins->dreg] = build_alloca (ctx, &klass->byval_arg);
                                args [0] = LLVMBuildBitCast (builder, addresses [ins->dreg], LLVMPointerType (LLVMInt8Type (), 0), "");
                                args [1] = LLVMConstInt (LLVMInt8Type (), 0, FALSE);
                                args [2] = LLVMConstInt (LLVMInt32Type (), mono_class_value_size (klass, NULL), FALSE);
@@ -2713,15 +3078,15 @@ mono_llvm_emit_method (MonoCompile *cfg)
                                        break;
                                case OP_LOADV_MEMBASE:
                                        if (!addresses [ins->dreg])
-                                               addresses [ins->dreg] = LLVMBuildAlloca (builder, type_to_llvm_type (ctx, &klass->byval_arg), "");
+                                               addresses [ins->dreg] = build_alloca (ctx, &klass->byval_arg);
                                        src = convert (ctx, LLVMBuildAdd (builder, convert (ctx, values [ins->inst_basereg], IntPtrType ()), LLVMConstInt (IntPtrType (), ins->inst_offset, FALSE), ""), LLVMPointerType (LLVMInt8Type (), 0));
                                        dst = LLVMBuildBitCast (builder, addresses [ins->dreg], LLVMPointerType (LLVMInt8Type (), 0), "");
                                        break;
                                case OP_VMOVE:
                                        if (!addresses [ins->sreg1])
-                                               addresses [ins->sreg1] = LLVMBuildAlloca (builder, type_to_llvm_type (ctx, &klass->byval_arg), "");
+                                               addresses [ins->sreg1] = build_alloca (ctx, &klass->byval_arg);
                                        if (!addresses [ins->dreg])
-                                               addresses [ins->dreg] = LLVMBuildAlloca (builder, type_to_llvm_type (ctx, &klass->byval_arg), "");
+                                               addresses [ins->dreg] = build_alloca (ctx, &klass->byval_arg);
                                        src = LLVMBuildBitCast (builder, addresses [ins->sreg1], LLVMPointerType (LLVMInt8Type (), 0), "");
                                        dst = LLVMBuildBitCast (builder, addresses [ins->dreg], LLVMPointerType (LLVMInt8Type (), 0), "");
                                        break;
@@ -2743,7 +3108,7 @@ mono_llvm_emit_method (MonoCompile *cfg)
                        }
                        case OP_LLVM_OUTARG_VT:
                                if (!addresses [ins->sreg1]) {
-                                       addresses [ins->sreg1] = LLVMBuildAlloca (builder, type_to_llvm_type (ctx, &ins->klass->byval_arg), "");
+                                       addresses [ins->sreg1] = build_alloca (ctx, &ins->klass->byval_arg);
                                        g_assert (values [ins->sreg1]);
                                        LLVMBuildStore (builder, values [ins->sreg1], addresses [ins->sreg1]);
                                }
@@ -2753,6 +3118,7 @@ mono_llvm_emit_method (MonoCompile *cfg)
                        /* 
                         * SIMD
                         */
+#if defined(TARGET_X86) || defined(TARGET_AMD64)
                        case OP_XZERO: {
                                values [ins->dreg] = LLVMConstNull (type_to_llvm_type (ctx, &ins->klass->byval_arg));
                                break;
@@ -2792,16 +3158,241 @@ mono_llvm_emit_method (MonoCompile *cfg)
                        case OP_PAND:
                                values [ins->dreg] = LLVMBuildAnd (builder, lhs, rhs, "");
                                break;
+                       case OP_POR:
+                               values [ins->dreg] = LLVMBuildOr (builder, lhs, rhs, "");
+                               break;
+                       case OP_PXOR:
+                               values [ins->dreg] = LLVMBuildXor (builder, lhs, rhs, "");
+                               break;
+                       case OP_ANDPS:
+                       case OP_ANDNPS:
+                       case OP_ORPS:
+                       case OP_XORPS:
+                       case OP_ANDPD:
+                       case OP_ANDNPD:
+                       case OP_ORPD:
+                       case OP_XORPD: {
+                               LLVMTypeRef t, rt;
+                               LLVMValueRef v;
+
+                               switch (ins->opcode) {
+                               case OP_ANDPS:
+                               case OP_ANDNPS:
+                               case OP_ORPS:
+                               case OP_XORPS:
+                                       t = LLVMVectorType (LLVMInt32Type (), 4);
+                                       rt = LLVMVectorType (LLVMFloatType (), 4);
+                                       break;
+                               case OP_ANDPD:
+                               case OP_ANDNPD:
+                               case OP_ORPD:
+                               case OP_XORPD:
+                                       t = LLVMVectorType (LLVMInt64Type (), 2);
+                                       rt = LLVMVectorType (LLVMDoubleType (), 2);
+                                       break;
+                               default:
+                                       t = LLVMInt32Type ();
+                                       rt = LLVMInt32Type ();
+                                       g_assert_not_reached ();
+                               }
+
+                               lhs = LLVMBuildBitCast (builder, lhs, t, "");
+                               rhs = LLVMBuildBitCast (builder, rhs, t, "");
+                               switch (ins->opcode) {
+                               case OP_ANDPS:
+                               case OP_ANDPD:
+                                       v = LLVMBuildAnd (builder, lhs, rhs, "");
+                                       break;
+                               case OP_ORPS:
+                               case OP_ORPD:
+                                       v = LLVMBuildOr (builder, lhs, rhs, "");
+                                       break;
+                               case OP_XORPS:
+                               case OP_XORPD:
+                                       v = LLVMBuildXor (builder, lhs, rhs, "");
+                                       break;
+                               case OP_ANDNPS:
+                               case OP_ANDNPD:
+                                       v = LLVMBuildAnd (builder, lhs, LLVMBuildNot (builder, rhs, ""), "");
+                                       break;
+                               }
+                               values [ins->dreg] = LLVMBuildBitCast (builder, v, rt, "");
+                               break;
+                       }
+                       case OP_MINPD:
+                       case OP_MINPS:
+                       case OP_MAXPD:
+                       case OP_MAXPS:
+                       case OP_PMIND_UN:
+                       case OP_PMINW_UN:
+                       case OP_PMINB_UN:
+                       case OP_PMAXD_UN:
+                       case OP_PMAXW_UN:
+                       case OP_PMAXB_UN: {
+                               LLVMValueRef args [2];
+
+                               args [0] = lhs;
+                               args [1] = rhs;
+
+                               values [ins->dreg] = LLVMBuildCall (builder, LLVMGetNamedFunction (module, simd_op_to_intrins (ins->opcode)), args, 2, dname);
+                               break;
+                       }
                        case OP_EXTRACT_R8:
                        case OP_EXTRACT_I8:
                        case OP_EXTRACT_I4:
                        case OP_EXTRACT_I2:
                        case OP_EXTRACT_U2:
                        case OP_EXTRACT_I1:
-                       case OP_EXTRACT_U1:
+                       case OP_EXTRACT_U1: {
+                               LLVMTypeRef t;
+
+                               switch (ins->opcode) {
+                               case OP_EXTRACT_R8:
+                                       t = LLVMVectorType (LLVMDoubleType (), 2);
+                                       break;
+                               case OP_EXTRACT_I8:
+                                       t = LLVMVectorType (LLVMInt64Type (), 2);
+                                       break;
+                               case OP_EXTRACT_I4:
+                                       t = LLVMVectorType (LLVMInt32Type (), 4);
+                                       break;
+                               case OP_EXTRACT_I2:
+                               case OP_EXTRACT_U2:
+                                       t = LLVMVectorType (LLVMInt16Type (), 8);
+                                       break;
+                               case OP_EXTRACT_I1:
+                               case OP_EXTRACT_U1:
+                                       t = LLVMVectorType (LLVMInt8Type (), 16);
+                                       break;
+                               default:
+                                       t = LLVMInt32Type ();
+                                       g_assert_not_reached ();
+                               }
+
+                               lhs = LLVMBuildBitCast (builder, lhs, t, "");
                                values [ins->dreg] = LLVMBuildExtractElement (builder, lhs, LLVMConstInt (LLVMInt32Type (), ins->inst_c0, FALSE), "");
                                break;
+                       }
+#endif
+
+                       case OP_DUMMY_USE:
+                               break;
+
+                       /*
+                        * EXCEPTION HANDLING
+                        */
+                       case OP_IMPLICIT_EXCEPTION:
+                               /* This marks a place where an implicit exception can happen */
+                               if (bb->region != -1)
+                                       LLVM_FAILURE (ctx, "implicit-exception");
+                               break;
+                       case OP_THROW: {
+                               MonoMethodSignature *throw_sig;
+                               LLVMValueRef callee, arg;
+
+                               if (!ctx->lmodule->throw) {
+                                       throw_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
+                                       throw_sig->ret = &mono_defaults.void_class->byval_arg;
+                                       throw_sig->params [0] = &mono_defaults.object_class->byval_arg;
+                                       if (cfg->compile_aot) {
+                                               callee = get_plt_entry (ctx, sig_to_llvm_sig (ctx, throw_sig, NULL), MONO_PATCH_INFO_INTERNAL_METHOD, "mono_arch_throw_exception");
+                                       } else {
+                                               callee = LLVMAddFunction (module, "mono_arch_throw_exception", sig_to_llvm_sig (ctx, throw_sig, NULL));
+
+#ifdef TARGET_X86
+                                               /* 
+                                                * LLVM doesn't push the exception argument, so we need a different
+                                                * trampoline.
+                                                */
+                                               LLVMAddGlobalMapping (ee, callee, resolve_patch (cfg, MONO_PATCH_INFO_INTERNAL_METHOD, "mono_arch_llvm_throw_exception"));
+#else
+                                               LLVMAddGlobalMapping (ee, callee, resolve_patch (cfg, MONO_PATCH_INFO_INTERNAL_METHOD, "mono_arch_throw_exception"));
+#endif
+                                       }
+
+                                       mono_memory_barrier ();
+                                       ctx->lmodule->throw = callee;
+                               }
+                               arg = convert (ctx, values [ins->sreg1], type_to_llvm_type (ctx, &mono_defaults.object_class->byval_arg));
+                               emit_call (ctx, bb, &builder, ctx->lmodule->throw, &arg, 1);
+                               break;
+                       }
+                       case OP_CALL_HANDLER: {
+                               /* 
+                                * We don't 'call' handlers, but instead simply branch to them.
+                                * The code generated by ENDFINALLY will branch back to us.
+                                */
+                               LLVMBasicBlockRef finally_bb, noex_bb;
+                               GSList *bb_list;
+
+                               finally_bb = get_bb (ctx, ins->inst_target_bb);
+
+                               bb_list = bblocks [ins->inst_target_bb->block_num].call_handler_return_bbs;
+
+                               /* 
+                                * Set the indicator variable for the finally clause.
+                                */
+                               lhs = bblocks [ins->inst_target_bb->block_num].finally_ind;
+                               g_assert (lhs);
+                               LLVMBuildStore (builder, LLVMConstInt (LLVMInt32Type (), g_slist_length (bb_list) + 1, FALSE), lhs);
+                               
+                               /* Branch to the finally clause */
+                               LLVMBuildBr (builder, finally_bb);
+
+                               noex_bb = gen_bb (ctx, "CALL_HANDLER_CONT_BB");
+                               // FIXME: Use a mempool
+                               bblocks [ins->inst_target_bb->block_num].call_handler_return_bbs = g_slist_append (bblocks [ins->inst_target_bb->block_num].call_handler_return_bbs, noex_bb);
 
+                               builder = ctx->builder = create_builder (ctx);
+                               LLVMPositionBuilderAtEnd (ctx->builder, noex_bb);
+
+                               bblocks [bb->block_num].end_bblock = noex_bb;
+                               break;
+                       }
+                       case OP_START_HANDLER: {
+                               break;
+                       }
+                       case OP_ENDFINALLY: {
+                               LLVMBasicBlockRef resume_bb;
+                               MonoBasicBlock *handler_bb;
+                               LLVMValueRef val, switch_ins;
+                               GSList *bb_list;
+
+                               handler_bb = g_hash_table_lookup (ctx->region_to_handler, GUINT_TO_POINTER (mono_get_block_region_notry (cfg, bb->region)));
+                               g_assert (handler_bb);
+                               lhs = bblocks [handler_bb->block_num].finally_ind;
+                               g_assert (lhs);
+
+                               bb_list = bblocks [handler_bb->block_num].call_handler_return_bbs;
+
+                               resume_bb = gen_bb (ctx, "ENDFINALLY_RESUME_BB");
+
+                               /* Load the finally variable */
+                               val = LLVMBuildLoad (builder, lhs, "");
+
+                               /* Reset the variable */
+                               LLVMBuildStore (builder, LLVMConstInt (LLVMInt32Type (), 0, FALSE), lhs);
+
+                               /* Branch to either resume_bb, or to the bblocks in bb_list */
+                               switch_ins = LLVMBuildSwitch (builder, val, resume_bb, g_slist_length (bb_list));
+                               /* 
+                                * The other targets are added at the end to handle OP_CALL_HANDLER
+                                * opcodes processed later.
+                                */
+                               bblocks [handler_bb->block_num].endfinally_switch = switch_ins;
+                               /*
+                               for (i = 0; i < g_slist_length (bb_list); ++i)
+                                       LLVMAddCase (switch_ins, LLVMConstInt (LLVMInt32Type (), i + 1, FALSE), g_slist_nth (bb_list, i)->data);
+                               */
+
+                               builder = ctx->builder = create_builder (ctx);
+                               LLVMPositionBuilderAtEnd (ctx->builder, resume_bb);
+
+                               LLVMBuildCall (builder, LLVMGetNamedFunction (module, "mono_resume_unwind"), NULL, 0, "");
+                               LLVMBuildUnreachable (builder);
+                               has_terminator = TRUE;
+                               break;
+                       }
                        default: {
                                char reason [128];
 
@@ -2830,11 +3421,16 @@ mono_llvm_emit_method (MonoCompile *cfg)
 
                if (bb == cfg->bb_exit && sig->ret->type == MONO_TYPE_VOID)
                        LLVMBuildRetVoid (builder);
+
+               if (bb == cfg->bb_entry)
+                       ctx->last_alloca = LLVMGetLastInstruction (get_bb (ctx, cfg->bb_entry));
        }
 
        /* Add incoming phi values */
        for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
-               GSList *l, *ins_list = g_hash_table_lookup (phi_nodes, GUINT_TO_POINTER (bb));
+               GSList *l, *ins_list;
+
+               ins_list = bblocks [bb->block_num].phi_nodes;
 
                for (l = ins_list; l; l = l->next) {
                        PhiNode *node = l->data;
@@ -2857,15 +3453,29 @@ mono_llvm_emit_method (MonoCompile *cfg)
                }
        }
 
+       /* Create the SWITCH statements for ENDFINALLY instructions */
+       for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
+               if (bblocks [bb->block_num].endfinally_switch) {
+                       LLVMValueRef switch_ins = bblocks [bb->block_num].endfinally_switch;
+                       GSList *bb_list = bblocks [bb->block_num].call_handler_return_bbs;
+
+                       for (i = 0; i < g_slist_length (bb_list); ++i)
+                               LLVMAddCase (switch_ins, LLVMConstInt (LLVMInt32Type (), i + 1, FALSE), g_slist_nth (bb_list, i)->data);
+               }
+       }
+
        if (cfg->verbose_level > 1)
                mono_llvm_dump_value (method);
 
+       mark_as_used (module, method);
+
        if (cfg->compile_aot) {
                /* Don't generate native code, keep the LLVM IR */
 
                /* Can't delete the method if it has an alias, so only add it if successful */
                if (debug_name) {
                        debug_alias = LLVMAddAlias (module, LLVMTypeOf (method), method, debug_name);
+                       LLVMSetLinkage (debug_alias, LLVMInternalLinkage);
                        LLVMSetVisibility (debug_alias, LLVMHiddenVisibility);
                }
 
@@ -2915,11 +3525,11 @@ mono_llvm_emit_method (MonoCompile *cfg)
        g_free (vreg_cli_types);
        g_free (pindexes);
        g_free (debug_name);
-       g_hash_table_destroy (phi_nodes);
        g_ptr_array_free (phi_values, TRUE);
        g_free (ctx->bblocks);
-       g_free (ctx->end_bblocks);
+       g_hash_table_destroy (ctx->region_to_handler);
        g_free (method_name);
+       g_ptr_array_free (bblock_list, TRUE);
 
        for (l = ctx->builders; l; l = l->next) {
                LLVMBuilderRef builder = l->data;
@@ -3030,6 +3640,9 @@ static void
 exception_cb (void *data)
 {
        MonoCompile *cfg;
+       MonoJitExceptionInfo *ei;
+       guint32 ei_len, i;
+       gpointer *type_info;
 
        cfg = TlsGetValue (current_cfg_tls_id);
        g_assert (cfg);
@@ -3040,7 +3653,20 @@ exception_cb (void *data)
         * An alternative would be to save it directly, and modify our unwinder to work
         * with it.
         */
-       cfg->encoded_unwind_ops = mono_unwind_get_ops_from_fde ((guint8*)data, &cfg->encoded_unwind_ops_len, NULL);
+       cfg->encoded_unwind_ops = mono_unwind_decode_fde ((guint8*)data, &cfg->encoded_unwind_ops_len, NULL, &ei, &ei_len, &type_info);
+
+       cfg->llvm_ex_info = mono_mempool_alloc0 (cfg->mempool, ei_len * sizeof (MonoJitExceptionInfo));
+       cfg->llvm_ex_info_len = ei_len;
+       memcpy (cfg->llvm_ex_info, ei, ei_len * sizeof (MonoJitExceptionInfo));
+       /* Fill the rest of the information from the type info */
+       for (i = 0; i < ei_len; ++i) {
+               MonoExceptionClause *clause = type_info [i];
+
+               cfg->llvm_ex_info [i].flags = clause->flags;
+               cfg->llvm_ex_info [i].data.catch_class = clause->data.catch_class;
+       }
+
+       g_free (ei);
 }
 
 static void
@@ -3065,6 +3691,9 @@ add_intrinsics (LLVMModuleRef module)
                LLVMAddFunction (module, "llvm.sin.f64", LLVMFunctionType (LLVMDoubleType (), params, 1, FALSE));
                LLVMAddFunction (module, "llvm.cos.f64", LLVMFunctionType (LLVMDoubleType (), params, 1, FALSE));
                LLVMAddFunction (module, "llvm.sqrt.f64", LLVMFunctionType (LLVMDoubleType (), params, 1, FALSE));
+
+               /* This isn't an intrinsic, instead llvm seems to special case it by name */
+               LLVMAddFunction (module, "fabs", LLVMFunctionType (LLVMDoubleType (), params, 1, FALSE));
        }
 
        {
@@ -3102,12 +3731,86 @@ add_intrinsics (LLVMModuleRef module)
                LLVMAddFunction (module, "llvm.smul.with.overflow.i64", LLVMFunctionType (LLVMStructType (ovf_res_i64, 2, FALSE), ovf_params_i64, 2, FALSE));
                LLVMAddFunction (module, "llvm.umul.with.overflow.i64", LLVMFunctionType (LLVMStructType (ovf_res_i64, 2, FALSE), ovf_params_i64, 2, FALSE));
        }
+
+       {
+               LLVMTypeRef struct_ptr = LLVMPointerType (LLVMStructType (NULL, 0, FALSE), 0);
+               LLVMTypeRef invariant_start_params [] = { LLVMInt64Type (), LLVMPointerType (LLVMInt8Type (), 0) };
+               LLVMTypeRef invariant_end_params [] = { struct_ptr, LLVMInt64Type (), LLVMPointerType (LLVMInt8Type (), 0) };
+
+               LLVMAddFunction (module, "llvm.invariant.start", LLVMFunctionType (struct_ptr, invariant_start_params, 2, FALSE));
+
+               LLVMAddFunction (module, "llvm.invariant.end", LLVMFunctionType (LLVMVoidType (), invariant_end_params, 3, FALSE));
+       }
+
+       /* EH intrinsics */
+       {
+               LLVMTypeRef arg_types [2];
+
+               arg_types [0] = LLVMPointerType (LLVMInt8Type (), 0);
+               arg_types [1] = LLVMPointerType (LLVMInt8Type (), 0);
+               LLVMAddFunction (module, "llvm.eh.selector", LLVMFunctionType (LLVMInt32Type (), arg_types, 2, TRUE));
+
+               LLVMAddFunction (module, "llvm.eh.exception", LLVMFunctionType (LLVMPointerType (LLVMInt8Type (), 0), NULL, 0, FALSE));
+
+               LLVMAddFunction (module, "mono_personality", LLVMFunctionType (LLVMVoidType (), NULL, 0, FALSE));
+
+               LLVMAddFunction (module, "mono_resume_unwind", LLVMFunctionType (LLVMVoidType (), NULL, 0, FALSE));
+       }
+
+       /* SSE intrinsics */
+       {
+               LLVMTypeRef vector_type, arg_types [2];
+
+               vector_type = LLVMVectorType (LLVMInt32Type (), 4);
+               arg_types [0] = vector_type;
+               arg_types [1] = vector_type;
+               LLVMAddFunction (module, "llvm.x86.sse41.pminud", LLVMFunctionType (vector_type, arg_types, 2, FALSE));                                 
+               LLVMAddFunction (module, "llvm.x86.sse41.pmaxud", LLVMFunctionType (vector_type, arg_types, 2, FALSE));                                 
+
+               vector_type = LLVMVectorType (LLVMInt16Type (), 8);
+               arg_types [0] = vector_type;
+               arg_types [1] = vector_type;
+               LLVMAddFunction (module, "llvm.x86.sse41.pminuw", LLVMFunctionType (vector_type, arg_types, 2, FALSE));                                 
+               LLVMAddFunction (module, "llvm.x86.sse41.pmaxuw", LLVMFunctionType (vector_type, arg_types, 2, FALSE));                                 
+
+               vector_type = LLVMVectorType (LLVMInt8Type (), 16);
+               arg_types [0] = vector_type;
+               arg_types [1] = vector_type;
+               LLVMAddFunction (module, "llvm.x86.sse41.pminub", LLVMFunctionType (vector_type, arg_types, 2, FALSE));                                 
+               LLVMAddFunction (module, "llvm.x86.sse41.pmaxub", LLVMFunctionType (vector_type, arg_types, 2, FALSE));                                 
+
+               vector_type = LLVMVectorType (LLVMDoubleType (), 2);
+               arg_types [0] = vector_type;
+               arg_types [1] = vector_type;
+               LLVMAddFunction (module, "llvm.x86.sse2.min.pd", LLVMFunctionType (vector_type, arg_types, 2, FALSE));                                  
+               LLVMAddFunction (module, "llvm.x86.sse2.max.pd", LLVMFunctionType (vector_type, arg_types, 2, FALSE));                                  
+
+               vector_type = LLVMVectorType (LLVMFloatType (), 4);
+               arg_types [0] = vector_type;
+               arg_types [1] = vector_type;
+               LLVMAddFunction (module, "llvm.x86.sse2.min.ps", LLVMFunctionType (vector_type, arg_types, 2, FALSE));                                  
+               LLVMAddFunction (module, "llvm.x86.sse2.max.ps", LLVMFunctionType (vector_type, arg_types, 2, FALSE));                                  
+       }
 }
 
 void
 mono_llvm_init (void)
 {
        current_cfg_tls_id = TlsAlloc ();
+}
+
+static void
+init_jit_module (void)
+{
+       if (jit_module_inited)
+               return;
+
+       mono_loader_lock ();
+
+       if (jit_module_inited) {
+               mono_loader_unlock ();
+               return;
+       }
 
        jit_module.module = LLVMModuleCreateWithName ("mono");
 
@@ -3116,14 +3819,22 @@ mono_llvm_init (void)
        add_intrinsics (jit_module.module);
 
        jit_module.llvm_types = g_hash_table_new (NULL, NULL);
+
+       LLVMAddGlobalMapping (ee, LLVMGetNamedFunction (jit_module.module, "mono_resume_unwind"), mono_resume_unwind);
+
+       jit_module_inited = TRUE;
+
+       mono_loader_unlock ();
 }
 
 void
 mono_llvm_cleanup (void)
 {
-       mono_llvm_dispose_ee (ee);
+       if (ee)
+               mono_llvm_dispose_ee (ee);
 
-       g_hash_table_destroy (jit_module.llvm_types);
+       if (jit_module.llvm_types)
+               g_hash_table_destroy (jit_module.llvm_types);
 }
 
 void
@@ -3154,13 +3865,18 @@ mono_llvm_create_aot_module (const char *got_symbol)
                LLVMSetInitializer (aot_module.got_var, LLVMConstNull (got_type));
        }
 
-       /* Add a method to generate the 'methods' symbol needed by the AOT compiler */
+       /* Add a dummy personality function */
        {
-               LLVMValueRef methods_method = LLVMAddFunction (aot_module.module, "methods", LLVMFunctionType (LLVMVoidType (), NULL, 0, FALSE));
-               LLVMBasicBlockRef bb = LLVMAppendBasicBlock (methods_method, "BB_ENTRY");
-               LLVMBuilderRef builder = LLVMCreateBuilder ();
-               LLVMPositionBuilderAtEnd (builder, bb);
-               LLVMBuildRetVoid (builder);
+               LLVMBasicBlockRef lbb;
+               LLVMBuilderRef lbuilder;
+               LLVMValueRef personality;
+
+               personality = LLVMAddFunction (aot_module.module, "mono_aot_personality", LLVMFunctionType (LLVMVoidType (), NULL, 0, FALSE));
+               LLVMSetLinkage (personality, LLVMPrivateLinkage);
+               lbb = LLVMAppendBasicBlock (personality, "BB0");
+               lbuilder = LLVMCreateBuilder ();
+               LLVMPositionBuilderAtEnd (lbuilder, lbb);
+               LLVMBuildRetVoid (lbuilder);
        }
 
        aot_module.llvm_types = g_hash_table_new (NULL, NULL);
@@ -3187,6 +3903,11 @@ mono_llvm_emit_aot_module (const char *filename, int got_size)
 
        mono_llvm_replace_uses_of (aot_module.got_var, real_got);
 
+       mark_as_used (aot_module.module, real_got);
+
+       /* Delete the dummy got so it doesn't become a global */
+       LLVMDeleteGlobal (aot_module.got_var);
+
 #if 0
        {
                char *verifier_err;