Don't run test-318 with gmcs.
[mono.git] / mono / mini / mini-s390.c
index 58125ad8619da37de82d3a664e57387b673bb6c1..cc377e1ca102362a4618efd94330df2e9ca94e02 100644 (file)
@@ -98,18 +98,18 @@ if (ins->flags & MONO_INST_BRLABEL) {                                                       \
 
 #undef DEBUG
 #define DEBUG(a) if (cfg->verbose_level > 1) a
-#define reg_is_freeable(r) ((r) >= 3 && (r) <= 10)
-#define freg_is_freeable(r) ((r) >= 1 && (r) <= 14)
 
 /*----------------------------------------*/
-/* use s390_r3-s390_r10 as temp registers */
+/* use s390_r2-s390_r5 as temp registers  */
 /*----------------------------------------*/
-#define S390_CALLER_REGS  (0x03f8)
+#define S390_CALLER_REGS  (0x10fc)
+#define reg_is_freeable(r) (S390_CALLER_REGS & 1 << (r))
 
 /*----------------------------------------*/
-/* use s390_f2-s390_f14 as temp registers */
+/* use s390_f1/s390_f3-s390_f15 as temps  */
 /*----------------------------------------*/
-#define S390_CALLER_FREGS (0x73f8)
+#define S390_CALLER_FREGS (0xfffa)
+#define freg_is_freeable(r) ((r) >= 1 && (r) <= 14)
 
 #define S390_TRACE_STACK_SIZE (5*sizeof(gint32)+3*sizeof(gdouble))
 
@@ -209,7 +209,6 @@ typedef struct {
 
 static guint32 * emit_memcpy (guint8 *, int, int, int, int, int);
 static void indent (int);
-static guint8 * restoreLMF(MonoCompile *, guint8 *);
 static guint8 * backUpStackPtr(MonoCompile *, guint8 *);
 static void decodeParm (MonoType *, void *, int);
 static void enter_method (MonoMethod *, RegParm *, char *);
@@ -247,6 +246,8 @@ static int indent_level = 0;
 
 static const char*const * ins_spec = s390;
 
+static gboolean tls_offset_inited = FALSE;
+
 /*====================== End of Global Variables ===================*/
 
 /*------------------------------------------------------------------*/
@@ -388,48 +389,6 @@ mono_arch_get_argument_info (MonoMethodSignature *csig,
 
 /*========================= End of Function ========================*/
 
-/*------------------------------------------------------------------*/
-/*                                                                  */
-/* Name                - restoreLMF                                        */
-/*                                                                  */
-/* Function    - Restore the LMF state prior to exiting a method.  */
-/*                                                                  */
-/*------------------------------------------------------------------*/
-
-static inline guint8 * 
-restoreLMF(MonoCompile *cfg, guint8 *code)
-{
-       int lmfOffset = 0;
-
-       s390_lr  (code, s390_r13, cfg->frame_reg);
-
-       lmfOffset = cfg->stack_usage -  sizeof(MonoLMF);
-
-       /*-------------------------------------------------*/
-       /* r13 = my lmf                                    */
-       /*-------------------------------------------------*/
-       s390_ahi (code, s390_r13, lmfOffset);
-
-       /*-------------------------------------------------*/
-       /* r6 = &jit_tls->lmf                              */
-       /*-------------------------------------------------*/
-       s390_l   (code, s390_r6, 0, s390_r13, G_STRUCT_OFFSET(MonoLMF, lmf_addr));
-
-       /*-------------------------------------------------*/
-       /* r0 = lmf.previous_lmf                           */
-       /*-------------------------------------------------*/
-       s390_l   (code, s390_r0, 0, s390_r13, G_STRUCT_OFFSET(MonoLMF, previous_lmf));
-
-       /*-------------------------------------------------*/
-       /* jit_tls->lmf = previous_lmf                     */
-       /*-------------------------------------------------*/
-       s390_l   (code, s390_r13, 0, s390_r6, 0);
-       s390_st  (code, s390_r0, 0, s390_r6, 0);
-       return (code);
-}
-
-/*========================= End of Function ========================*/
-
 /*------------------------------------------------------------------*/
 /*                                                                  */
 /* Name                - backStackPtr.                                     */
@@ -443,7 +402,7 @@ backUpStackPtr(MonoCompile *cfg, guint8 *code)
 {
        int stackSize = cfg->stack_usage;
 
-       if (s390_is_imm16 (cfg->stack_usage)) {
+       if (s390_is_uimm16 (cfg->stack_usage)) {
                s390_ahi  (code, STK_BASE, cfg->stack_usage);
        } else { 
                while (stackSize > 32767) {
@@ -928,8 +887,11 @@ mono_arch_cpu_optimizazions (guint32 *exclude_mask)
 {
        guint32 opts = 0;
 
-       /* no s390-specific optimizations yet */
+       /*----------------------------------------------------------*/
+       /* no s390-specific optimizations yet                       */
+       /*----------------------------------------------------------*/
        *exclude_mask = MONO_OPT_INLINE|MONO_OPT_LINEARS;
+//     *exclude_mask = MONO_OPT_INLINE;
        return opts;
 }
 
@@ -1019,10 +981,12 @@ GList *
 mono_arch_get_global_int_regs (MonoCompile *cfg)
 {
        GList *regs = NULL;
-       int i, top = 12;
+       int i, top = 13;
 
-       for (i = 3; i < top; ++i)
-               regs = g_list_prepend (regs, GUINT_TO_POINTER (i));
+       for (i = 8; i < top; ++i) {
+               if (cfg->frame_reg != i)
+                       regs = g_list_prepend (regs, GUINT_TO_POINTER (i));
+       }
 
        return regs;
 }
@@ -1355,7 +1319,7 @@ enum_retvalue:
 /*------------------------------------------------------------------*/
 
 void
-mono_arch_allocate_vars (MonoCompile *m)
+mono_arch_allocate_vars (MonoCompile *cfg)
 {
        MonoMethodSignature *sig;
        MonoMethodHeader *header;
@@ -1366,7 +1330,7 @@ mono_arch_allocate_vars (MonoCompile *m)
        int frame_reg = STK_BASE;
        int sArg, eArg;
 
-       header  = ((MonoMethodNormal *)m->method)->header;
+       header  = mono_method_get_header (cfg->method);
 
        /*---------------------------------------------------------*/    
        /* We use the frame register also for any method that has  */ 
@@ -1378,29 +1342,29 @@ mono_arch_allocate_vars (MonoCompile *m)
        /* before stack unwinding happens) when the filter code    */
        /* would call any method.                                  */
        /*---------------------------------------------------------*/    
-       if ((m->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses)
+       if ((cfg->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses)
                frame_reg = s390_r11;
 
-       m->frame_reg = frame_reg;
+       cfg->frame_reg = frame_reg;
 
        if (frame_reg != STK_BASE) 
-               m->used_int_regs |= 1 << frame_reg;             
+               cfg->used_int_regs |= 1 << frame_reg;           
 
-       sig     = m->method->signature;
+       sig     = cfg->method->signature;
        
        cinfo   = calculate_sizes (sig, &sz, sig->pinvoke);
 
        if (cinfo->struct_ret) {
-               m->ret->opcode = OP_REGVAR;
-               m->ret->inst_c0 = s390_r2;
+               cfg->ret->opcode = OP_REGVAR;
+               cfg->ret->inst_c0 = s390_r2;
        } else {
                /* FIXME: handle long and FP values */
                switch (sig->ret->type) {
                case MONO_TYPE_VOID:
                        break;
                default:
-                       m->ret->opcode = OP_REGVAR;
-                       m->ret->dreg    = s390_r2;
+                       cfg->ret->opcode = OP_REGVAR;
+                       cfg->ret->dreg   = s390_r2;
                        break;
                }
        }
@@ -1412,10 +1376,10 @@ mono_arch_allocate_vars (MonoCompile *m)
        /* to point at the local variables.                             */
        /* add parameter area size for called functions                 */
        /*--------------------------------------------------------------*/
-       offset = (m->param_area + S390_MINIMAL_STACK_SIZE);
+       offset = (cfg->param_area + S390_MINIMAL_STACK_SIZE);
 
        if (cinfo->struct_ret) {
-               inst               = m->ret;
+               inst               = cfg->ret;
                offset             = S390_ALIGN(offset, sizeof(gpointer));
                inst->inst_offset  = offset;
                inst->opcode       = OP_REGOFFSET;
@@ -1424,7 +1388,7 @@ mono_arch_allocate_vars (MonoCompile *m)
        }
 
        if (sig->hasthis) {
-               inst = m->varinfo [0];
+               inst = cfg->varinfo [0];
                if (inst->opcode != OP_REGVAR) {
                        inst->opcode       = OP_REGOFFSET;
                        inst->inst_basereg = frame_reg;
@@ -1440,7 +1404,7 @@ mono_arch_allocate_vars (MonoCompile *m)
        eArg = sig->param_count + sArg;
 
        for (iParm = sArg; iParm < eArg; ++iParm) {
-               inst = m->varinfo [curinst];
+               inst = cfg->varinfo [curinst];
                if (inst->opcode != OP_REGVAR) {
                        switch (cinfo->args[iParm].regtype) {
                                case RegTypeStructByAddr :
@@ -1483,10 +1447,11 @@ mono_arch_allocate_vars (MonoCompile *m)
                curinst++;
        }
 
-       curinst = m->locals_start;
-       for (iVar = curinst; iVar < m->num_varinfo; ++iVar) {
-               inst = m->varinfo [iVar];
-               if (inst->opcode == OP_REGVAR)
+       curinst = cfg->locals_start;
+       for (iVar = curinst; iVar < cfg->num_varinfo; ++iVar) {
+               inst = cfg->varinfo [iVar];
+               if ((inst->flags & MONO_INST_IS_DEAD) || 
+                   (inst->opcode == OP_REGVAR))
                        continue;
 
                /*--------------------------------------------------*/
@@ -1504,25 +1469,25 @@ mono_arch_allocate_vars (MonoCompile *m)
                inst->opcode       = OP_REGOFFSET;
                inst->inst_basereg = frame_reg;
                offset            += size;
-               //DEBUG (g_print("allocating local %d to %d\n", iVar, inst->inst_offset));
+               DEBUG (g_print("allocating local %d to %d\n", iVar, inst->inst_offset));
        }
 
        /*------------------------------------------------------*/
        /* Allow space for the trace method stack area if needed*/
        /*------------------------------------------------------*/
-       if (mono_jit_trace_calls != NULL && mono_trace_eval (m)) 
+       if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg)) 
                offset += S390_TRACE_STACK_SIZE;
 
        /*------------------------------------------------------*/
        /* Reserve space to save LMF and caller saved registers */
        /*------------------------------------------------------*/
-       if (m->method->save_lmf)
+       if (cfg->method->save_lmf)
                offset += sizeof (MonoLMF);
 
        /*------------------------------------------------------*/
        /* align the offset                                     */
        /*------------------------------------------------------*/
-       m->stack_offset = S390_ALIGN(offset, S390_STACK_ALIGNMENT);
+       cfg->stack_offset = S390_ALIGN(offset, S390_STACK_ALIGNMENT);
 
 }
 
@@ -1566,7 +1531,7 @@ mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb,
        cfg->flags       |= MONO_CFG_HAS_CALLS;
 
        if (cinfo->struct_ret)
-               call->used_iregs |= 1 << cinfo->struct_ret;
+               call->used_iregs |= 1 << cinfo->ret.reg;
 
        for (i = 0; i < n; ++i) {
                ainfo = cinfo->args + i;
@@ -2577,10 +2542,10 @@ mono_arch_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
        while (ins) {
                spec = ins_spec [ins->opcode];
                DEBUG (print_ins (i, ins));
-               if (spec [MONO_INST_CLOB] == 'c') {
-                       MonoCallInst * call = (MonoCallInst*)ins;
-                       int j;
-               }
+//             if (spec [MONO_INST_CLOB] == 'c') {
+//                     MonoCallInst * call = (MonoCallInst*)ins;
+//                     int j;
+//             }
                if (spec [MONO_INST_SRC1]) {
                        if (spec [MONO_INST_SRC1] == 'f')
                                reginfo1 = reginfof;
@@ -2613,7 +2578,7 @@ mono_arch_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
                        if (reginfod [ins->dreg].born_in == 0 || reginfod [ins->dreg].born_in > i)
                                reginfod [ins->dreg].born_in = i;
                        if (spec [MONO_INST_DEST] == 'l') {
-                               /* result in eax:edx, the virtual register is allocated sequentially */
+                               /* result in R2/R3, the virtual register is allocated sequentially */
                                reginfod [ins->dreg + 1].prev_use = reginfod [ins->dreg + 1].last_use;
                                reginfod [ins->dreg + 1].last_use = i;
                                if (reginfod [ins->dreg + 1].born_in == 0 || reginfod [ins->dreg + 1].born_in > i)
@@ -2762,7 +2727,10 @@ mono_arch_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
                                                create_copy_ins (cfg, ins->dreg, s390_r3, ins);
                                        }
                                }
-                               if (reg_is_freeable (val) && hreg >= 0 && (reginfo [hreg].born_in >= i && !(cur_iregs & (1 << val)))) {
+                               if (reg_is_freeable (val) && 
+                                   hreg >= 0 && 
+                                    (reginfo [hreg].born_in >= i && 
+                                     !(cur_iregs & (1 << val)))) {
                                        DEBUG (g_print ("\tfreeable %s (R%d)\n", mono_arch_regname (val), hreg));
                                        mono_regstate_free_int (rs, val);
                                }
@@ -2795,7 +2763,6 @@ mono_arch_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
                                                /* the register gets spilled after this inst */
                                                spill = -val -1;
                                        }
-                                       //g_assert (val == -1); /* source cannot be spilled */
                                        val = mono_regstate_alloc_float (rs, src1_mask);
                                        if (val < 0)
                                                val = get_float_register_spilling (cfg, tmp, ins, src1_mask, ins->sreg1);
@@ -2920,16 +2887,6 @@ mono_arch_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
                                }
                        }
                }
-               /*if (reg_is_freeable (ins->sreg1) && prev_sreg1 >= 0 && reginfo [prev_sreg1].born_in >= i) {
-                       DEBUG (g_print ("freeable %s\n", mono_arch_regname (ins->sreg1)));
-                       mono_regstate_free_int (rs, ins->sreg1);
-               }
-               if (reg_is_freeable (ins->sreg2) && prev_sreg2 >= 0 && reginfo [prev_sreg2].born_in >= i) {
-                       DEBUG (g_print ("freeable %s\n", mono_arch_regname (ins->sreg2)));
-                       mono_regstate_free_int (rs, ins->sreg2);
-               }*/
-               
-               //DEBUG (print_ins (i, ins));
                tmp = tmp->next;
        }
 }
@@ -3065,49 +3022,49 @@ guint8 cond;
 
                switch (ins->opcode) {
                case OP_STOREI1_MEMBASE_IMM: {
-                       s390_lhi (code, s390_r14, ins->inst_imm);
+                       s390_lhi (code, s390_r0, ins->inst_imm);
                        if (s390_is_uimm12(ins->inst_offset))
-                               s390_stc (code, s390_r14, 0, ins->inst_destbasereg, ins->inst_offset);
+                               s390_stc (code, s390_r0, 0, ins->inst_destbasereg, ins->inst_offset);
                        else {
                                s390_basr (code, s390_r13, 0);
                                s390_j    (code, 4);
                                s390_word (code, ins->inst_offset);
                                s390_l    (code, s390_r13, 0, s390_r13, 4);
-                               s390_stc  (code, s390_r14, s390_r13, ins->inst_destbasereg, 0);
+                               s390_stc  (code, s390_r0, s390_r13, ins->inst_destbasereg, 0);
                        }
                }
                        break;
                case OP_STOREI2_MEMBASE_IMM: {
-                       s390_lhi (code, s390_r14, ins->inst_imm);
+                       s390_lhi (code, s390_r0, ins->inst_imm);
                        if (s390_is_uimm12(ins->inst_offset)) {
-                               s390_sth (code, s390_r14, 0, ins->inst_destbasereg, ins->inst_offset);
+                               s390_sth (code, s390_r0, 0, ins->inst_destbasereg, ins->inst_offset);
                        } else {
                                s390_basr (code, s390_r13, 0);
                                s390_j    (code, 4);
                                s390_word (code, ins->inst_offset);
                                s390_l    (code, s390_r13, 0, s390_r13, 4);
-                               s390_sth  (code, s390_r14, s390_r13, ins->inst_destbasereg, 0);
+                               s390_sth  (code, s390_r0, s390_r13, ins->inst_destbasereg, 0);
                        }
                }
                        break;
                case OP_STORE_MEMBASE_IMM:
                case OP_STOREI4_MEMBASE_IMM: {
-                       if (s390_is_imm16(ins->inst_imm)) {
-                               s390_lhi  (code, s390_r14, ins->inst_imm);
+                       if (s390_is_uimm16(ins->inst_imm)) {
+                               s390_lhi  (code, s390_r0, ins->inst_imm);
                        } else {
                                s390_basr (code, s390_r13, 0);
                                s390_j    (code, 4);
                                s390_word (code, ins->inst_imm);
-                               s390_l    (code, s390_r14, 0, s390_r13, 4);
+                               s390_l    (code, s390_r0, 0, s390_r13, 4);
                        }
                        if (s390_is_uimm12(ins->inst_offset)) {
-                               s390_st  (code, s390_r14, 0, ins->inst_destbasereg, ins->inst_offset);
+                               s390_st  (code, s390_r0, 0, ins->inst_destbasereg, ins->inst_offset);
                        } else {
                                s390_basr (code, s390_r13, 0);
                                s390_j    (code, 4);
                                s390_word (code, ins->inst_offset);
                                s390_l    (code, s390_r13, 0, s390_r13, 4);
-                               s390_st   (code, s390_r14, s390_r13, ins->inst_destbasereg, 0);
+                               s390_st   (code, s390_r0, s390_r13, ins->inst_destbasereg, 0);
                        }
                }
                        break;
@@ -3167,7 +3124,7 @@ guint8 cond;
                        if (s390_is_uimm12(ins->inst_offset))
                                s390_l    (code, ins->dreg, 0, ins->inst_basereg, ins->inst_offset);
                        else {
-                               if (s390_is_imm16(ins->inst_offset)) {
+                               if (s390_is_uimm16(ins->inst_offset)) {
                                        s390_lhi (code, s390_r13, ins->inst_offset);
                                        s390_l   (code, ins->dreg, s390_r13, ins->inst_basereg, 0);
                                } else {
@@ -3299,7 +3256,7 @@ guint8 cond;
                }
                        break;
                case OP_COMPARE_IMM: {
-                       if (s390_is_imm16 (ins->inst_imm)) {
+                       if (s390_is_uimm16 (ins->inst_imm)) {
                                s390_lhi  (code, s390_r0, ins->inst_imm);
                                if ((ins->next) && 
                                    ((ins->next->opcode >= CEE_BNE_UN) &&
@@ -3370,7 +3327,7 @@ guint8 cond;
                                }
                                s390_al   (code, ins->dreg, 0, s390_r13, 4);
                        } else {
-                               if (s390_is_imm16 (ins->inst_imm)) {
+                               if (s390_is_uimm16 (ins->inst_imm)) {
                                        if (ins->dreg != ins->sreg1) {
                                                s390_lr   (code, ins->dreg, ins->sreg1);
                                        }
@@ -3388,7 +3345,7 @@ guint8 cond;
                }
                        break;
                case OP_ADC_IMM: {
-                       if (s390_is_imm16 (ins->inst_imm)) {
+                       if (s390_is_uimm16 (ins->inst_imm)) {
                                if (ins->dreg != ins->sreg1) {
                                        s390_lr   (code, ins->dreg, ins->sreg1);
                                } 
@@ -3461,9 +3418,25 @@ guint8 cond;
                        s390_slbr (code, ins->dreg, ins->sreg2);
                }
                        break;
-               case OP_SUBCC_IMM:
+               case OP_SUBCC_IMM: {
+                       if (s390_is_uimm16 (-ins->inst_imm)) {
+                               if (ins->dreg != ins->sreg1) {
+                                       s390_lr   (code, ins->dreg, ins->sreg1);
+                               }
+                               s390_ahi  (code, ins->dreg, -ins->inst_imm);
+                       } else {
+                               s390_basr (code, s390_r13, 0);
+                               s390_j    (code, 4);
+                               s390_word (code, ins->inst_imm);
+                               if (ins->dreg != ins->sreg1) {
+                                       s390_lr   (code, ins->dreg, ins->sreg1);
+                               }
+                               s390_sl   (code, ins->dreg, 0, s390_r13, 4);
+                       }
+               }
+                       break;
                case OP_SUB_IMM: {
-                       if (s390_is_imm16 (-ins->inst_imm)) {
+                       if (s390_is_uimm16 (-ins->inst_imm)) {
                                if (ins->dreg != ins->sreg1) {
                                        s390_lr   (code, ins->dreg, ins->sreg1);
                                }
@@ -3480,10 +3453,18 @@ guint8 cond;
                }
                        break;
                case OP_SBB_IMM: {
-                       s390_basr (code, s390_r13, 0);
-                       s390_j    (code, 4);
-                       s390_word (code, ins->inst_imm);
-                       s390_sl   (code, ins->dreg, 0, s390_r13, 4);
+                       if (ins->dreg != ins->sreg1) {
+                               s390_lr    (code, ins->dreg, ins->sreg1);
+                       }
+                       if (s390_is_uimm16 (-ins->inst_imm)) {
+                               s390_lhi   (code, s390_r0, ins->inst_imm);
+                               s390_slbr  (code, ins->dreg, s390_r0);
+                       } else {
+                               s390_basr (code, s390_r13, 0);
+                               s390_j    (code, 4);
+                               s390_word (code, ins->inst_imm);
+                               s390_slb  (code, ins->dreg, 0, s390_r13, 4);
+                       }
                }
                        break;
                case CEE_SUB_OVF: {
@@ -3539,7 +3520,7 @@ guint8 cond;
                }
                        break;
                case OP_AND_IMM: {
-                       if (s390_is_imm16 (ins->inst_imm)) {
+                       if (s390_is_uimm16 (ins->inst_imm)) {
                                s390_lhi  (code, s390_r0, ins->inst_imm);
                                if (ins->dreg != ins->sreg1) {
                                        s390_lr   (code, ins->dreg, ins->sreg1);
@@ -3571,7 +3552,7 @@ guint8 cond;
                }
                        break;
                case OP_DIV_IMM: {
-                       if (s390_is_imm16 (ins->inst_imm)) {
+                       if (s390_is_uimm16 (ins->inst_imm)) {
                                s390_lhi  (code, s390_r13, ins->inst_imm);
                                s390_lr   (code, s390_r0, ins->sreg1);
                        } else {
@@ -3582,7 +3563,7 @@ guint8 cond;
                                s390_l    (code, s390_r13, 0, s390_r13, 4);
                        }
                        s390_srda (code, s390_r0, 0, 32);
-                       s390_dr   (code, s390_r0, ins->sreg2);
+                       s390_dr   (code, s390_r0, s390_r13);
                        s390_lr   (code, ins->dreg, s390_r1);
                }
                        break;
@@ -3600,7 +3581,7 @@ guint8 cond;
                }
                        break;
                case OP_REM_IMM: {
-                       if (s390_is_imm16 (ins->inst_imm)) {
+                       if (s390_is_uimm16 (ins->inst_imm)) {
                                s390_lhi  (code, s390_r13, ins->inst_imm);
                                s390_lr   (code, s390_r0, ins->sreg1);
                        } else {
@@ -3611,7 +3592,7 @@ guint8 cond;
                                s390_l    (code, s390_r13, 0, s390_r13, 4);
                        }
                        s390_srda (code, s390_r0, 0, 32);
-                       s390_dr   (code, s390_r0, ins->sreg2);
+                       s390_dr   (code, s390_r0, s390_r13);
                        s390_lr   (code, ins->dreg, s390_r0);
                }
                        break;
@@ -3631,19 +3612,20 @@ guint8 cond;
                }
                        break;
                case OP_OR_IMM: {
-                       if (s390_is_imm16 (ins->inst_imm)) {
+                       if (s390_is_uimm16 (ins->inst_imm)) {
                                s390_lhi  (code, s390_r0, ins->inst_imm);
                                if (ins->dreg != ins->sreg1) {
                                        s390_lr   (code, ins->dreg, ins->sreg1);
                                }
                                s390_or   (code, ins->dreg, s390_r0);
                        } else {
-                               s390_bras (code, s390_r13, 4);
+                               s390_basr (code, s390_r13, 0);
+                               s390_j    (code, 4);
                                s390_word (code, ins->inst_imm);
                                if (ins->dreg != ins->sreg1) {
                                        s390_lr   (code, ins->dreg, ins->sreg1);
                                }
-                               s390_o    (code, ins->dreg, 0, s390_r13, 0);
+                               s390_o    (code, ins->dreg, 0, s390_r13, 4);
                        }
                }
                        break;
@@ -3663,7 +3645,7 @@ guint8 cond;
                }
                        break;
                case OP_XOR_IMM: {
-                       if (s390_is_imm16 (ins->inst_imm)) {
+                       if (s390_is_uimm16 (ins->inst_imm)) {
                                s390_lhi  (code, s390_r0, ins->inst_imm);
                                if (ins->dreg != ins->sreg1) {
                                        s390_lr   (code, ins->dreg, ins->sreg1);
@@ -3750,7 +3732,7 @@ guint8 cond;
                }
                        break;
                case OP_MUL_IMM: {
-                       if (s390_is_imm16 (ins->inst_imm)) {
+                       if (s390_is_uimm16 (ins->inst_imm)) {
                                s390_lhi  (code, s390_r13, ins->inst_imm);
                        } else {
                                s390_basr (code, s390_r13, 0);
@@ -3794,22 +3776,22 @@ guint8 cond;
                        break;
                case OP_LMUL: {
                        s390_l    (code, s390_r0, 0, ins->sreg1, 4);
-                       s390_lr   (code, s390_r14, s390_r0);
                        s390_srda (code, s390_r0, 0, 32);
                        s390_m    (code, s390_r0, 0, ins->sreg2, 4);
-                       s390_srl  (code, s390_r14, 0, 31);
-                       s390_a    (code, s390_r14, 0, ins->sreg1, 0);
+                       s390_l    (code, s390_r0, 0, ins->sreg1, 4);
+                       s390_srl  (code, s390_r0, 0, 31);
+                       s390_a    (code, s390_r0, 0, ins->sreg1, 0);
                        s390_l    (code, s390_r13, 0, ins->sreg2, 0);
                        s390_srl  (code, s390_r13, 0, 31);
                        s390_ms   (code, s390_r13, 0, ins->sreg1, 4);
-                       s390_ar   (code, s390_r14, s390_r13);
-                       s390_st   (code, s390_r14, 0, ins->dreg, 0);
+                       s390_ar   (code, s390_r0, s390_r13);
+                       s390_st   (code, s390_r0, 0, ins->dreg, 0);
                        s390_st   (code, s390_r1, 0, ins->dreg, 4);
                }
                        break;  
                case OP_ICONST:
                case OP_SETREGIMM: {
-                       if (s390_is_imm16(ins->inst_c0)) {
+                       if (s390_is_uimm16(ins->inst_c0)) {
                                s390_lhi  (code, ins->dreg, ins->inst_c0);
                        } else {
                                s390_basr (code, s390_r13, 0);
@@ -3869,7 +3851,7 @@ guint8 cond;
                case CEE_JMP: {
                        int fParm;
                        if (cfg->method->save_lmf)
-                               code = restoreLMF(cfg, code);
+                               restoreLMF(code, cfg->frame_reg, cfg->stack_usage);
 
                        if (cfg->flags & MONO_CFG_HAS_TAIL) {
                                s390_lm (code, s390_r2, s390_r5, STK_BASE, 
@@ -3897,7 +3879,7 @@ guint8 cond;
                        s390_basr (code, s390_r13, 0);
                        s390_j    (code, 4);
                        s390_word (code, cfg->sig_cookie);
-                       s390_l    (code, ins->sreg1, 0, s390_r13, 4);
+                       s390_mvc  (code, 4, ins->sreg1, 0, s390_r13, 4);
                }
                        break;
                case OP_FCALL: {
@@ -3988,6 +3970,13 @@ guint8 cond;
                        s390_brasl (code, s390_r14, 0);
                }
                        break;
+               case OP_RETHROW: {
+                       s390_lr (code, s390_r2, ins->sreg1);
+                       mono_add_patch_info (cfg, code-cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
+                                            (gpointer)"mono_arch_rethrow_exception");
+                       s390_brasl (code, s390_r14, 0);
+               }
+                       break;
                case OP_START_HANDLER: {
                        if (s390_is_uimm12 (ins->inst_left->inst_offset)) {
                                s390_st   (code, s390_r14, 0, 
@@ -4265,17 +4254,18 @@ guint8 cond;
                case OP_LCONV_TO_OVF_I: {
                        /* Valid ints: 0xffffffff:8000000 to 00000000:0x7f000000 */
                        short int *o[5];
-                       s390_ltr  (code, ins->sreg2, ins->sreg2);
-                       s390_jnl  (code, 0); CODEPTR(code, o[0]);
                        s390_ltr  (code, ins->sreg1, ins->sreg1);
+                       s390_jnl  (code, 0); CODEPTR(code, o[0]);
+                       s390_ltr  (code, ins->sreg2, ins->sreg2);
                        s390_jnl  (code, 0); CODEPTR(code, o[1]);
                        s390_lhi  (code, s390_r13, -1);
-                       s390_cr   (code, ins->sreg1, s390_r13);
+                       s390_cr   (code, ins->sreg2, s390_r13);
                        s390_jnz  (code, 0); CODEPTR(code, o[2]);
-                       if (ins->dreg != ins->sreg2)
-                               s390_lr   (code, ins->dreg, ins->sreg2);
+                       if (ins->dreg != ins->sreg1)
+                               s390_lr   (code, ins->dreg, ins->sreg1);
                        s390_j    (code, 0); CODEPTR(code, o[3]);
                        PTRSLOT(code, o[0]);
+                       s390_ltr  (code, ins->sreg2, ins->sreg2);
                        s390_jz   (code, 0); CODEPTR(code, o[4]);
                        PTRSLOT(code, o[1]);
                        PTRSLOT(code, o[2]);
@@ -4432,7 +4422,7 @@ guint8 cond;
                                                   ins->inst_offset, ins->sreg1, ins->inst_imm);
                                } else {
                                        s390_lr   (code, s390_r0, ins->dreg);
-                                       if (s390_is_imm16 (ins->inst_offset)) {
+                                       if (s390_is_uimm16 (ins->inst_offset)) {
                                                s390_ahi  (code, s390_r0, ins->inst_offset);
                                        } else {
                                                s390_basr (code, s390_r13, 0);
@@ -4440,8 +4430,9 @@ guint8 cond;
                                                s390_word (code, ins->inst_offset);
                                                s390_a    (code, s390_r0, 0, s390_r13, 4);
                                        }
+                                       s390_lr   (code, s390_r14, s390_r12);
                                        s390_lr   (code, s390_r12, ins->sreg1);
-                                       if (s390_is_imm16 (ins->inst_imm)) {
+                                       if (s390_is_uimm16 (ins->inst_imm)) {
                                                s390_ahi  (code, s390_r12, ins->inst_imm);
                                        } else {
                                                s390_basr (code, s390_r13, 0);
@@ -4453,6 +4444,7 @@ guint8 cond;
                                        s390_lr   (code, s390_r13, s390_r1);
                                        s390_mvcle(code, s390_r0, s390_r12, 0, 0);
                                        s390_jo   (code, -2);
+                                       s390_lr   (code, s390_r12, s390_r14);
                                }
                        }
                }
@@ -4724,16 +4716,17 @@ mono_arch_emit_prolog (MonoCompile *cfg)
        MonoBasicBlock *bb;
        MonoMethodSignature *sig;
        MonoInst *inst;
-       int alloc_size, pos, max_offset, i, lmfOffset;
+       int alloc_size, pos, max_offset, i;
        guint8 *code;
        CallInfo *cinfo;
        size_data sz;
        int tracing = 0;
+       int lmfOffset;                                                          \
 
        if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
                tracing = 1;
 
-       cfg->code_size   = 256;
+       cfg->code_size   = 512;
        cfg->native_code = code = g_malloc (cfg->code_size);
 
        if (cfg->flags & MONO_CFG_HAS_TAIL) {
@@ -4753,7 +4746,7 @@ mono_arch_emit_prolog (MonoCompile *cfg)
 
        cfg->stack_usage = alloc_size;
        s390_lr   (code, s390_r11, STK_BASE);
-       if (s390_is_imm16 (-alloc_size)) {
+       if (s390_is_uimm16 (alloc_size)) {
                s390_ahi  (code, STK_BASE, -alloc_size);
        } else { 
                int stackSize = alloc_size;
@@ -4924,56 +4917,61 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                /*---------------------------------------------------------------*/
                /* we build the MonoLMF structure on the stack - see mini-s390.h */
                /*---------------------------------------------------------------*/
-               lmfOffset = alloc_size - sizeof(MonoLMF);
-
-               s390_lr    (code, s390_r13, cfg->frame_reg);
-               s390_ahi   (code, s390_r13, lmfOffset);
-
-               /*---------------------------------------------------------------*/
-               /* Set lmf.lmf_addr = jit_tls->lmf                               */
-               /*---------------------------------------------------------------*/
-               s390_st    (code, s390_r2, 0, s390_r13, G_STRUCT_OFFSET(MonoLMF, lmf_addr));
-
-               /*---------------------------------------------------------------*/
-               /* Get current lmf                                               */
-               /*---------------------------------------------------------------*/
-               s390_l     (code, s390_r0, 0, s390_r2, 0);
-
-               /*---------------------------------------------------------------*/
-               /* Set our lmf as the current lmf                                */
-               /*---------------------------------------------------------------*/
-               s390_st    (code, s390_r13, 0, s390_r2, 0);
-
-               /*---------------------------------------------------------------*/
-               /* Have our lmf.previous_lmf point to the last lmf               */
-               /*---------------------------------------------------------------*/
-               s390_st    (code, s390_r0, 0, s390_r13, G_STRUCT_OFFSET(MonoLMF, previous_lmf));
-
-               /*---------------------------------------------------------------*/
-               /* save method info                                              */
-               /*---------------------------------------------------------------*/
-               s390_basr  (code, s390_r1, 0);
-               s390_j     (code, 4);
-               s390_word  (code, method);
-               s390_l     (code, s390_r1, 0, s390_r1, 4);
-               s390_st    (code, s390_r1, 0, s390_r13, G_STRUCT_OFFSET(MonoLMF, method));
-
-               /*---------------------------------------------------------------*/
-               /* save the current IP                                           */
-               /*---------------------------------------------------------------*/
+               lmfOffset = alloc_size - sizeof(MonoLMF);       
+                                                                                       
+               s390_lr    (code, s390_r13, cfg->frame_reg);            
+               s390_ahi   (code, s390_r13, lmfOffset);                                 
+                                                                                       
+               /*---------------------------------------------------------------*/     
+               /* Set lmf.lmf_addr = jit_tls->lmf                               */     
+               /*---------------------------------------------------------------*/     
+               s390_st    (code, s390_r2, 0, s390_r13,                                 
+                           G_STRUCT_OFFSET(MonoLMF, lmf_addr));                        
+                                                                                       
+               /*---------------------------------------------------------------*/     
+               /* Get current lmf                                               */     
+               /*---------------------------------------------------------------*/     
+               s390_l     (code, s390_r0, 0, s390_r2, 0);                              
+                                                                                       
+               /*---------------------------------------------------------------*/     
+               /* Set our lmf as the current lmf                                */     
+               /*---------------------------------------------------------------*/     
+               s390_st    (code, s390_r13, 0, s390_r2, 0);                             
+                                                                                       
+               /*---------------------------------------------------------------*/     
+               /* Have our lmf.previous_lmf point to the last lmf               */     
+               /*---------------------------------------------------------------*/     
+               s390_st    (code, s390_r0, 0, s390_r13,                                 
+                           G_STRUCT_OFFSET(MonoLMF, previous_lmf));                    
+                                                                                       
+               /*---------------------------------------------------------------*/     
+               /* save method info                                              */     
+               /*---------------------------------------------------------------*/     
+               s390_basr  (code, s390_r1, 0);                                          
+               s390_j     (code, 4);                                                   
+               s390_word  (code, method);                                              
+               s390_l     (code, s390_r1, 0, s390_r1, 4);                      
+               s390_st    (code, s390_r1, 0, s390_r13,                                 
+                           G_STRUCT_OFFSET(MonoLMF, method));                          
+                                                                               
+               /*---------------------------------------------------------------*/     
+               /* save the current IP                                           */     
+               /*---------------------------------------------------------------*/     
                s390_lr    (code, s390_r1, cfg->frame_reg);
-               s390_st    (code, s390_r1, 0, s390_r13, G_STRUCT_OFFSET(MonoLMF, ebp));
-               s390_l     (code, s390_r1, 0, s390_r1, S390_RET_ADDR_OFFSET);
-               s390_la    (code, s390_r1, 0, s390_r1, 0);
-               s390_st    (code, s390_r1, 0, s390_r13, G_STRUCT_OFFSET(MonoLMF, eip));
-
-               /*---------------------------------------------------------------*/
-               /* Save general and floating point registers                     */
-               /*---------------------------------------------------------------*/
-               s390_stm   (code, s390_r2, s390_r12, s390_r13, G_STRUCT_OFFSET(MonoLMF, gregs[2]));
-               for (i = 0; i < 16; i++) {
-                       s390_std  (code, i, 0, s390_r13, G_STRUCT_OFFSET(MonoLMF, fregs[i]));
-               }
+               s390_st    (code, s390_r1, 0, s390_r13, G_STRUCT_OFFSET(MonoLMF, ebp)); 
+               s390_l     (code, s390_r1, 0, s390_r1, S390_RET_ADDR_OFFSET);           
+               s390_la    (code, s390_r1, 0, s390_r1, 0);                              
+               s390_st    (code, s390_r1, 0, s390_r13, G_STRUCT_OFFSET(MonoLMF, eip)); 
+                                                                                       
+               /*---------------------------------------------------------------*/     
+               /* Save general and floating point registers                     */     
+               /*---------------------------------------------------------------*/     
+               s390_stm   (code, s390_r2, s390_r12, s390_r13,                          
+                           G_STRUCT_OFFSET(MonoLMF, gregs[2]));                        
+               for (i = 0; i < 16; i++) {                                              
+                       s390_std  (code, i, 0, s390_r13,                                
+                                  G_STRUCT_OFFSET(MonoLMF, fregs[i]));                 
+               }                                                                       
 
                /*---------------------------------------------------------------*/
                /* Restore the parameter registers now that we've set up the lmf */
@@ -5008,9 +5006,7 @@ mono_arch_emit_epilog (MonoCompile *cfg)
 {
        MonoJumpInfo *patch_info;
        MonoMethod *method = cfg->method;
-       MonoMethodSignature *sig = method->signature;
-       MonoInst *inst;
-       int i, tracing = 0;
+       int tracing = 0;
        guint8 *code;
 
        code = cfg->native_code + cfg->code_len;
@@ -5021,7 +5017,7 @@ mono_arch_emit_epilog (MonoCompile *cfg)
        }
        
        if (method->save_lmf) 
-               code = restoreLMF(cfg, code);
+               restoreLMF(code, cfg->frame_reg, cfg->stack_usage);
 
        if (cfg->flags & MONO_CFG_HAS_ALLOCA) 
                s390_l   (code, STK_BASE, 0, STK_BASE, 0);
@@ -5089,6 +5085,50 @@ mono_arch_emit_epilog (MonoCompile *cfg)
 void
 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
 {
+#ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
+       pthread_t       self = pthread_self();
+       pthread_attr_t  attr;
+       void            *stAddr = NULL;
+       size_t          stSize  = 0;
+       struct sigaltstack sa;
+#endif
+
+       if (!tls_offset_inited) {
+               tls_offset_inited = TRUE;
+
+//             lmf_tls_offset = read_tls_offset_from_method (mono_get_lmf_addr);
+//             appdomain_tls_offset = read_tls_offset_from_method (mono_domain_get);
+//             thread_tls_offset = read_tls_offset_from_method (mono_thread_current);
+       }               
+
+#ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
+
+       /*----------------------------------------------------------*/
+       /* Determine stack boundaries                               */
+       /*----------------------------------------------------------*/
+       if (!mono_running_on_valgrind ()) {
+#ifdef HAVE_PTHREAD_GETATTR_NP
+               pthread_getattr_np( self, &attr );
+#elif HAVE_PTHREAD_ATTR_GET_NP
+               pthread_attr_get_np( self, &attr );
+#endif
+               pthread_attr_getstack( &attr, &stAddr, &stSize );
+       }
+
+
+       /*----------------------------------------------------------*/
+       /* Setup an alternate signal stack                          */
+       /*----------------------------------------------------------*/
+       tls->stack_size        = stSize;
+       tls->signal_stack      = g_malloc (SIGNAL_STACK_SIZE);
+       tls->signal_stack_size = SIGNAL_STACK_SIZE;
+
+       sa.ss_sp    = tls->signal_stack;
+       sa.ss_size  = SIGNAL_STACK_SIZE;
+       sa.ss_flags = SS_ONSTACK;
+       sigaltstack (&sa, NULL);
+#endif
+
 }
 
 /*========================= End of Function ========================*/
@@ -5104,6 +5144,18 @@ mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
 void
 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
 {
+#ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
+       struct sigaltstack sa;
+
+       sa.ss_sp    = tls->signal_stack;
+       sa.ss_size  = SIGNAL_STACK_SIZE;
+       sa.ss_flags = SS_DISABLE;
+       sigaltstack (&sa, NULL);
+
+       if (tls->signal_stack)
+               g_free (tls->signal_stack);
+#endif
+
 }
 
 /*========================= End of Function ========================*/
@@ -5186,11 +5238,15 @@ mono_arch_print_tree (MonoInst *tree, int arity)
        switch (tree->opcode) {
                case OP_S390_LOADARG:
                case OP_S390_ARGPTR:
-               case OP_S390_STKARG:
                        printf ("[0x%x(%s)]", tree->inst_offset, 
                                mono_arch_regname (tree->inst_basereg));
                        done = 1;
                        break;
+               case OP_S390_STKARG:
+                       printf ("[0x%x(previous_frame)]", 
+                               tree->inst_offset); 
+                       done = 1;
+                       break;
                case OP_S390_MOVE:
                        printf ("[0x%x(%d,%s),0x%x(%s)]",
                                tree->inst_offset, tree->unused,
@@ -5227,17 +5283,41 @@ guint32
 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
 {
        /* FIXME: */
-       return 3;
+       return 2;
 }
 
 /*========================= End of Function ========================*/
 
+/*------------------------------------------------------------------*/
+/*                                                                  */
+/* Name                - mono_arch_get_domain_intrinsic                    */
+/*                                                                  */
+/* Function    -                                                   */
+/*                                                                 */
+/* Returns     -                                                   */
+/*                                                                  */
+/*------------------------------------------------------------------*/
+
 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
 {
        return NULL;
 }
 
+/*========================= End of Function ========================*/
+
+/*------------------------------------------------------------------*/
+/*                                                                  */
+/* Name                - mono_arch_get_thread_intrinsic                    */
+/*                                                                  */
+/* Function    -                                                   */
+/*                                                                 */
+/* Returns     -                                                   */
+/*                                                                  */
+/*------------------------------------------------------------------*/
+
 MonoInst* mono_arch_get_thread_intrinsic (MonoCompile* cfg)
 {
        return NULL;
 }
+
+/*========================= End of Function ========================*/