2004-09-24 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mono / mini / mini-s390.c
index 101c5c7ec7625c64e60c107efa415b0f23753f03..5da1af2e8920bac83bdb89da3557c40cb737e3b7 100644 (file)
@@ -19,7 +19,7 @@
 /*------------------------------------------------------------------*/
 
 #define NOT_IMPLEMENTED(x) \
-        g_error ("FIXME: %s is not yet implemented. (trampoline)", x);
+        g_error ("FIXME: %s is not yet implemented.", x);
 
 #define EMIT_COND_BRANCH(ins,cond)                                                     \
 {                                                                                      \
@@ -207,8 +207,10 @@ typedef struct {
 /*                   P r o t o t y p e s                            */
 /*------------------------------------------------------------------*/
 
-static guint32 *emit_memcpy (guint8 *, int, int, int, int, int);
+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 *);
 static void leave_method (MonoMethod *, ...);
@@ -386,6 +388,75 @@ 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.                                     */
+/*                                                                  */
+/* Function    - Restore Stack Pointer to previous frame.          */
+/*                                                                  */
+/*------------------------------------------------------------------*/
+
+static inline guint8 *
+backUpStackPtr(MonoCompile *cfg, guint8 *code)
+{
+       int stackSize = cfg->stack_usage;
+
+       if (s390_is_imm16 (cfg->stack_usage)) {
+               s390_ahi  (code, STK_BASE, cfg->stack_usage);
+       } else { 
+               while (stackSize > 32767) {
+                       s390_ahi  (code, STK_BASE, 32767);
+                       stackSize -= 32767;
+               }
+               s390_ahi  (code, STK_BASE, stackSize);
+       }
+       return (code);
+}
+
+/*========================= End of Function ========================*/
+
 /*------------------------------------------------------------------*/
 /*                                                                  */
 /* Name                - indent                                            */
@@ -442,10 +513,10 @@ enum_parmtype:
                                printf ("[CHAR:%p], ", *((int *) curParm));
                                break;
                        case MONO_TYPE_I1 :
-                               printf ("[INT1:%d], ", *((int *) curParm+3));
+                               printf ("[INT1:%d], ", *((int *) curParm));
                                break; 
                        case MONO_TYPE_I2 :
-                               printf ("[INT2:%d], ", *((int *) curParm+2));
+                               printf ("[INT2:%d], ", *((int *) curParm));
                                break; 
                        case MONO_TYPE_I4 :
                                printf ("[INT4:%d], ", *((int *) curParm));
@@ -454,10 +525,13 @@ enum_parmtype:
                                printf ("[UINT1:%ud], ", *((unsigned int *) curParm));
                                break; 
                        case MONO_TYPE_U2 :
-                               printf ("[UINT2:%ud], ", *((unsigned int *) curParm));
+                               printf ("[UINT2:%ud], ", *((guint16 *) curParm));
                                break; 
                        case MONO_TYPE_U4 :
-                               printf ("[UINT4:%ud], ", *((unsigned int *) curParm));
+                               printf ("[UINT4:%ud], ", *((guint32 *) curParm));
+                               break; 
+                       case MONO_TYPE_U8 :
+                               printf ("[UINT8:%ul], ", *((guint64 *) curParm));
                                break; 
                        case MONO_TYPE_STRING : {
                                MonoString *s = *((MonoString **) curParm);
@@ -551,6 +625,7 @@ enter_method (MonoMethod *method, RegParm *rParm, char *sp)
        MonoJitArgumentInfo *arg_info;
        MonoMethodSignature *sig;
        char *fname;
+       guint32 ip;
        CallInfo *cinfo;
        ArgInfo *ainfo;
        size_data sz;
@@ -561,7 +636,8 @@ enter_method (MonoMethod *method, RegParm *rParm, char *sp)
        printf ("ENTER: %s(", fname);
        g_free (fname);
 
-       printf (") ip: %p sp: %p\n", __builtin_return_address (1), sp);
+       ip  = (*(guint32 *) (sp+S390_RET_ADDR_OFFSET)) & 0x7fffffff;
+       printf (") ip: %p sp: %p - ", ip, sp); 
 
        if (rParm == NULL)
                return;
@@ -634,6 +710,17 @@ enter_method (MonoMethod *method, RegParm *rParm, char *sp)
                                                   ainfo->vtsize);
                                        }
                                break;
+                       case RegTypeStructByAddr :
+                               if (ainfo->reg != STK_BASE) 
+                                       curParm = &(rParm->gr[ainfo->reg-2]);
+                               else
+                                       curParm = sp+ainfo->offset;
+
+                               decodeParm(sig->params[i], 
+                                          *((char **) curParm),
+                                          ainfo->vtsize);
+                               break;
+                               
                        default :
                                printf("???, ");
                }
@@ -657,6 +744,7 @@ leave_method (MonoMethod *method, ...)
 {
        MonoType *type;
        char *fname;
+       guint32 ip;
        va_list ap;
 
        va_start(ap, method);
@@ -718,13 +806,13 @@ handle_enum:
        }
        case MONO_TYPE_I: {
                int *val = va_arg (ap, int*);
-               printf ("[INT:%p]", val);
+               printf ("[INT:%d]", val);
                printf("]");
                break;
        }
        case MONO_TYPE_U: {
                int *val = va_arg (ap, int*);
-               printf ("[UINT:%p]", val);
+               printf ("[UINT:%d]", val);
                printf("]");
                break;
        }
@@ -769,9 +857,14 @@ handle_enum:
                printf ("[LONG:%lld]", l);
                break;
        }
+       case MONO_TYPE_R4: {
+               double f = va_arg (ap, double);
+               printf ("[FLOAT4:%f]\n", (float) f);
+               break;
+       }
        case MONO_TYPE_R8: {
                double f = va_arg (ap, double);
-               printf ("[FP:%g]\n", f);
+               printf ("[FLOAT8:%g]\n", f);
                break;
        }
        case MONO_TYPE_VALUETYPE: 
@@ -789,10 +882,12 @@ handle_enum:
                }
                break;
        default:
-               printf ("(unknown return type %x)", method->signature->ret->type);
+               printf ("(unknown return type %x)", 
+                       method->signature->ret->type);
        }
 
-       printf (" ip: %p\n", __builtin_return_address (0));
+       ip = ((gint32) __builtin_return_address (0)) & 0x7fffffff;
+       printf (" ip: %p\n", ip);
 }
 
 /*========================= End of Function ========================*/
@@ -809,6 +904,13 @@ handle_enum:
 void
 mono_arch_cpu_init (void)
 {
+       guint mode = 1;
+
+       /*--------------------------------------*/      
+       /* Set default rounding mode for FP     */
+       /*--------------------------------------*/      
+       __asm__ ("SRNM\t%0\n\t"
+               : : "m" (mode));
 }
 
 /*========================= End of Function ========================*/
@@ -1007,13 +1109,13 @@ calculate_sizes (MonoMethodSignature *sig, size_data *sz,
 
        fr                = 0;
        gr                = s390_r2;
+       nParm             = 0;
        cinfo->struct_ret = 0;
        sz->retStruct     = 0;
        sz->stack_size    = S390_MINIMAL_STACK_SIZE;
        sz->code_size     = 0;
        sz->local_size    = 0;
 
-       nParm = 0;
        /*----------------------------------------------------------*/
        /* We determine the size of the return code/stack in case we*/
        /* need to reserve a register to be used to address a stack */
@@ -1076,6 +1178,7 @@ enum_retvalue:
                        sz->stack_size   += S390_ALIGN(size, align);
                        gr++;
                         break;
+               case MONO_TYPE_TYPEDBYREF:
                case MONO_TYPE_VOID:
                        break;
                default:
@@ -1164,25 +1267,25 @@ enum_retvalue:
                                case 2:
                                case 4:
                                        add_general(&gr, sz, cinfo->args+nParm, TRUE);
-                                       cinfo->args[nParm].size    = sizeof(int);
+                                       cinfo->args[nParm].size    = size;
                                        cinfo->args[nParm].regtype = RegTypeStructByVal; 
                                        nParm++;
-                                       sz->local_size += sizeof(long);
+                                       sz->local_size            += sizeof(long);
                                        break;
                                case 8:
                                        add_general(&gr, sz, cinfo->args+nParm, FALSE);
                                        cinfo->args[nParm].size    = sizeof(long long);
                                        cinfo->args[nParm].regtype = RegTypeStructByVal; 
                                        nParm++;
-                                       sz->local_size += sizeof(long);
+                                       sz->local_size            += sizeof(long);
                                        break;
                                default:
                                        add_general(&gr, sz, cinfo->args+nParm, TRUE);
                                        cinfo->args[nParm].size    = sizeof(int);
-                                       cinfo->args[nParm].regtype = RegTypeStructByVal
+                                       cinfo->args[nParm].regtype = RegTypeStructByAddr
                                        cinfo->args[nParm].vtsize  = size;
-                                       sz->code_size  += 40;
-                                       sz->local_size += size;
+                                       sz->code_size             += 40;
+                                       sz->local_size            += size;
                                        if (cinfo->args[nParm].reg == STK_BASE)
                                                sz->local_size += sizeof(gpointer);
                                        nParm++;
@@ -1219,8 +1322,6 @@ enum_retvalue:
                                sz->code_size += 4;
                                fr += 2;
                        } else {
-                               sz->stack_size  = S390_ALIGN(sz->stack_size, 
-                                                            S390_STACK_ALIGNMENT);
                                cinfo->args[nParm].offset  = sz->stack_size;
                                cinfo->args[nParm].reg     = STK_BASE;
                                cinfo->args[nParm].regtype = RegTypeBase;
@@ -1234,8 +1335,6 @@ enum_retvalue:
                }
        }
 
-
-       /* align stack size */
        cinfo->stack_usage = S390_ALIGN(sz->stack_size+sz->local_size, 
                                        S390_STACK_ALIGNMENT);
        return (cinfo);
@@ -1269,17 +1368,17 @@ mono_arch_allocate_vars (MonoCompile *m)
 
        header  = ((MonoMethodNormal *)m->method)->header;
 
-       /* 
-        * We use the frame register also for any method that has
-        * filter clauses. This way, when the handlers are called,
-        * the code will reference local variables using the frame reg instead of
-        * the stack pointer: if we had to restore the stack pointer, we'd
-        * corrupt the method frames that are already on the stack (since
-        * filters get called before stack unwinding happens) when the filter
-        * code would call any method.
-        */ 
-//     if ((m->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses)
-       if (m->flags & MONO_CFG_HAS_ALLOCA) 
+       /*---------------------------------------------------------*/    
+       /* We use the frame register also for any method that has  */ 
+       /* filter clauses. This way, when the handlers are called, */
+       /* the code will reference local variables using the frame */
+       /* reg instead of the stack pointer: if we had to restore  */
+       /* the stack pointer, we'd corrupt the method frames that  */
+       /* are already on the stack (since filters get called      */
+       /* before stack unwinding happens) when the filter code    */
+       /* would call any method.                                  */
+       /*---------------------------------------------------------*/    
+       if ((m->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses)
                frame_reg = s390_r11;
 
        m->frame_reg = frame_reg;
@@ -1343,21 +1442,22 @@ mono_arch_allocate_vars (MonoCompile *m)
        for (iParm = sArg; iParm < eArg; ++iParm) {
                inst = m->varinfo [curinst];
                if (inst->opcode != OP_REGVAR) {
-                       if (cinfo->args[iParm].regtype == RegTypeStructByVal) {
-                               if (cinfo->args[iParm].vtsize != 0) {
+                       switch (cinfo->args[iParm].regtype) {
+                               case RegTypeStructByAddr :
                                        inst->opcode       = OP_S390_LOADARG;
                                        inst->inst_basereg = frame_reg;
-                                       size               = sizeof(long);
+                                       size               = abs(cinfo->args[iParm].vtsize);
                                        offset             = S390_ALIGN(offset, size);
                                        inst->inst_offset  = offset; 
-                               } else {
+                                       break;
+                               case RegTypeStructByVal :
                                        inst->opcode       = OP_S390_ARGPTR;
                                        inst->inst_basereg = frame_reg;
                                        size               = cinfo->args[iParm].size;
                                        offset             = S390_ALIGN(offset, size);
                                        inst->inst_offset  = offset;
-                               }
-                       } else {
+                                       break;
+                               default :
                                if (cinfo->args[iParm].reg != STK_BASE) {
                                        inst->opcode       = OP_REGOFFSET;
                                        inst->inst_basereg = frame_reg;
@@ -1374,7 +1474,6 @@ mono_arch_allocate_vars (MonoCompile *m)
                                                              : 0);
                                        inst->inst_offset  = cinfo->args[iParm].offset + 
                                                             size;
-//                                     inst->unused       = stackOffset;
                                        inst->unused       = 0;
                                        size               = sizeof(long);
                                } 
@@ -1390,8 +1489,11 @@ mono_arch_allocate_vars (MonoCompile *m)
                if (inst->opcode == OP_REGVAR)
                        continue;
 
-               /* inst->unused indicates native sized value types, this is used by the
-               * pinvoke wrappers when they call functions returning structure */
+               /*--------------------------------------------------*/
+               /* inst->unused indicates native sized value types, */
+               /* this is used by the pinvoke wrappers when they   */
+               /* call functions returning structure               */
+               /*--------------------------------------------------*/
                if (inst->unused && MONO_TYPE_ISSTRUCT (inst->inst_vtype))
                        size = mono_class_native_size (inst->inst_vtype->data.klass, &align);
                else
@@ -1405,12 +1507,6 @@ mono_arch_allocate_vars (MonoCompile *m)
                //DEBUG (g_print("allocating local %d to %d\n", iVar, inst->inst_offset));
        }
 
-//     if (sig->hasthis) 
-//             curinst = sArg = 1;
-//     else 
-//             curinst = sArg = 0;
-//
-
        /*------------------------------------------------------*/
        /* Allow space for the trace method stack area if needed*/
        /*------------------------------------------------------*/
@@ -1449,7 +1545,8 @@ mono_arch_allocate_vars (MonoCompile *m)
 /*------------------------------------------------------------------*/
 
 MonoCallInst*
-mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, int is_virtual) {
+mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, 
+                      MonoCallInst *call, int is_virtual) {
        MonoInst *arg, *in;
        MonoMethodSignature *sig;
        int i, n, lParamArea;
@@ -1467,10 +1564,6 @@ mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call,
        lParamArea        = cinfo->stack_usage - S390_MINIMAL_STACK_SIZE;
        cfg->param_area   = MAX (cfg->param_area, lParamArea);
        cfg->flags       |= MONO_CFG_HAS_CALLS;
-       /*----------------------------------------------------------*/ 
-       /* should set more info in call, such as the stack space    */
-       /* used by the args that needs to be added back to esp      */
-       /*----------------------------------------------------------*/ 
 
        if (cinfo->struct_ret)
                call->used_iregs |= 1 << cinfo->struct_ret;
@@ -1498,8 +1591,12 @@ mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call,
                                if (arg->type == STACK_I8)
                                        call->used_iregs |= 1 << (ainfo->reg + 1);
                        } else if (ainfo->regtype == RegTypeStructByAddr) {
-                               arg->unused = ainfo->reg;
                                call->used_iregs |= 1 << ainfo->reg;
+                               arg->sreg1     = ainfo->reg;
+                               arg->opcode    = OP_OUTARG_VT;
+                               arg->unused    = -ainfo->vtsize;
+                               arg->inst_imm  = ainfo->offset;
+                               arg->sreg2     = ainfo->offparm + S390_MINIMAL_STACK_SIZE;
                        } else if (ainfo->regtype == RegTypeStructByVal) {
                                if (ainfo->reg != STK_BASE) {
                                        switch (ainfo->size) {
@@ -1517,12 +1614,9 @@ mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call,
                                                call->used_iregs |= 1 << ainfo->reg;
                                        }
                                } 
-                               arg->sreg1    = ainfo->reg;
-                               arg->opcode   = OP_OUTARG_VT;
-                               if (ainfo->vtsize != 0)
-                                       arg->unused = -ainfo->vtsize;
-                               else
-                                       arg->unused = ainfo->size;
+                               arg->sreg1     = ainfo->reg;
+                               arg->opcode    = OP_OUTARG_VT;
+                               arg->unused    = ainfo->size;
                                arg->inst_imm  = ainfo->offset;
                                arg->sreg2     = ainfo->offparm + S390_MINIMAL_STACK_SIZE;
                        } else if (ainfo->regtype == RegTypeBase) {
@@ -1531,16 +1625,17 @@ mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call,
                                arg->inst_imm = ainfo->offset;
                                call->used_fregs |= 1 << ainfo->reg;
                        } else if (ainfo->regtype == RegTypeFP) {
-                               arg->opcode = OP_OUTARG_R8;
                                arg->unused = ainfo->reg;
                                call->used_fregs |= 1 << ainfo->reg;
                                if (ainfo->size == 4) {
-                                       /* we reduce the precision */
                                        MonoInst *conv;
+                                       arg->opcode     = OP_OUTARG_R4;
                                        MONO_INST_NEW (cfg, conv, OP_FCONV_TO_R4);
                                        conv->inst_left = arg->inst_left;
-                                       arg->inst_left = conv;
+                                       arg->inst_left  = conv;
                                }
+                               else
+                                       arg->opcode = OP_OUTARG_R8;
                        } else {
                                g_assert_not_reached ();
                        }
@@ -2856,18 +2951,40 @@ emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size,
        /* sreg is a float, dreg is an integer reg. */
        if (is_signed) {
                s390_cfdbr (code, dreg, 5, sreg);
+               switch (size) {
+                       case 1:
+                               s390_lhi  (code, s390_r0, 0);
+                               s390_lhi  (code, s390_r13, 0xff);
+                               s390_ltr  (code, dreg, dreg);
+                               s390_jnl  (code, 4);
+                               s390_lhi  (code, s390_r0, 0x80);
+                               s390_nr   (code, dreg, s390_r13);
+                               s390_or   (code, dreg, s390_r0);
+                               break;
+               }
        } else {
                s390_basr   (code, s390_r13, 0);
                s390_j      (code, 10);
-               s390_double (code, 0x41e0000000000000);
-               s390_double (code, 0x41f0000000000000);
-               s390_ldr    (code, s390_f0, sreg);
-               s390_cdb    (code, s390_f0, 0, s390_r13, 0);
+               s390_llong  (code, 0x41e0000000000000);
+               s390_llong  (code, 0x41f0000000000000);
+               s390_ldr    (code, s390_f15, sreg);
+               s390_cdb    (code, s390_f15, 0, s390_r13, 0);
                s390_jl     (code, 10);
-               s390_sdb    (code, s390_f0, 0, s390_r13, 8);
-               s390_cfdbr  (code, dreg, 7, s390_f0);
-               s390_j      (code, 5);
+               s390_sdb    (code, s390_f15, 0, s390_r13, 8);
+               s390_cfdbr  (code, dreg, 7, s390_f15);
+               s390_j      (code, 4);
                s390_cfdbr  (code, dreg, 5, sreg);
+               switch (size) {
+                       case 1: 
+                               s390_lhi  (code, s390_r0, 0xff);
+                               s390_nr   (code, dreg, s390_r0);
+                               break;
+                       case 2:
+                               s390_lhi  (code, s390_r0, -1);
+                               s390_srl  (code, s390_r0, 0, 16);
+                               s390_nr   (code, dreg, s390_r0);
+                               break;
+               }
        }
        return code;
 }
@@ -2944,6 +3061,8 @@ guint8 cond;
                        code = cfg->native_code + offset;
                }
 
+               mono_debug_record_line_number (cfg, ins, offset);
+
                switch (ins->opcode) {
                case OP_STOREI1_MEMBASE_IMM: {
                        s390_lhi (code, s390_r14, ins->inst_imm);
@@ -2963,7 +3082,7 @@ guint8 cond;
                        if (s390_is_uimm12(ins->inst_offset)) {
                                s390_sth (code, s390_r14, 0, ins->inst_destbasereg, ins->inst_offset);
                        } else {
-                               s390_basr (code, s390_r14, 0);
+                               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);
@@ -3129,7 +3248,7 @@ guint8 cond;
                                s390_lr   (code, ins->dreg, ins->sreg1);
                        }
                        s390_nr   (code, s390_r0, ins->sreg1);
-                       s390_jl   (code, 7);
+                       s390_jz   (code, 7);
                        s390_lhi  (code, s390_r13, -1);
                        s390_sll  (code, s390_r13, 0, 8);
                        s390_or   (code, ins->dreg, s390_r13);
@@ -3137,11 +3256,12 @@ guint8 cond;
                        break;
                case CEE_CONV_I2: {
                        s390_lhi  (code, s390_r0, 0x80);
+                       s390_sll  (code, s390_r0, 0, 8);
                        if (ins->dreg != ins->sreg1) {
                                s390_lr   (code, ins->dreg, ins->sreg1);
                        }
                        s390_nr   (code, s390_r0, ins->sreg1);
-                       s390_jl   (code, 7);
+                       s390_jz   (code, 7);
                        s390_lhi  (code, s390_r13, -1);
                        s390_sll  (code, s390_r13, 0, 16);
                        s390_or   (code, ins->dreg, s390_r13);
@@ -3168,7 +3288,11 @@ guint8 cond;
                case OP_COMPARE: {
                        if ((ins->next) && 
                            ((ins->next->opcode >= CEE_BNE_UN) &&
-                            (ins->next->opcode <= CEE_BLT_UN)))
+                            (ins->next->opcode <= CEE_BLT_UN)) || 
+                           ((ins->next->opcode >= OP_COND_EXC_NE_UN) &&
+                            (ins->next->opcode <= OP_COND_EXC_LT_UN)) ||
+                           ((ins->next->opcode == OP_CLT_UN) ||
+                            (ins->next->opcode == OP_CGT_UN)))
                                s390_clr  (code, ins->sreg1, ins->sreg2);
                        else
                                s390_cr   (code, ins->sreg1, ins->sreg2);
@@ -3178,8 +3302,12 @@ guint8 cond;
                        if (s390_is_imm16 (ins->inst_imm)) {
                                s390_lhi  (code, s390_r0, ins->inst_imm);
                                if ((ins->next) && 
-                                   ((ins->next->opcode >= CEE_BNE_UN) &&
-                                   (ins->next->opcode <= CEE_BLT_UN)))
+                                   ((ins->next->opcode >= CEE_BNE_UN) &&
+                                    (ins->next->opcode <= CEE_BLT_UN)) || 
+                                   ((ins->next->opcode >= OP_COND_EXC_NE_UN) &&
+                                    (ins->next->opcode <= OP_COND_EXC_LT_UN)) ||
+                                   ((ins->next->opcode == OP_CLT_UN) ||
+                                    (ins->next->opcode == OP_CGT_UN)))
                                        s390_clr  (code, ins->sreg1, s390_r0);
                                else
                                        s390_cr   (code, ins->sreg1, s390_r0);
@@ -3189,8 +3317,12 @@ guint8 cond;
                                s390_j    (code, 4);
                                s390_word (code, ins->inst_imm);
                                if ((ins->next) && 
-                                   ((ins->next->opcode >= CEE_BNE_UN) &&
-                                   (ins->next->opcode <= CEE_BLT_UN)))
+                                   ((ins->next->opcode >= CEE_BNE_UN) &&
+                                    (ins->next->opcode <= CEE_BLT_UN)) || 
+                                   ((ins->next->opcode >= OP_COND_EXC_NE_UN) &&
+                                    (ins->next->opcode <= OP_COND_EXC_LT_UN)) ||
+                                   ((ins->next->opcode == OP_CLT_UN) &&
+                                    (ins->next->opcode == OP_CGT_UN)))
                                        s390_cl   (code, ins->sreg1, 0, s390_r13, 4);
                                else
                                        s390_c    (code, ins->sreg1, 0, s390_r13, 4);
@@ -3226,6 +3358,7 @@ guint8 cond;
                        s390_alcr (code, ins->dreg, ins->sreg2);
                }
                        break;
+               case OP_ADDCC_IMM:
                case OP_ADD_IMM: {
                        if ((ins->next) &&
                            (ins->next->opcode == OP_ADC_IMM)) {
@@ -3270,11 +3403,48 @@ guint8 cond;
                        }
                }
                        break;
+               case CEE_ADD_OVF: {
+                       if (ins->dreg != ins->sreg1) {
+                               s390_lr   (code, ins->dreg, ins->sreg1);
+                       }
+                       s390_ar   (code, ins->dreg, ins->sreg2);
+                       EMIT_COND_SYSTEM_EXCEPTION (S390_CC_OV, "OverflowException");
+               }
+                       break;
+               case CEE_ADD_OVF_UN: {
+                       if (ins->dreg != ins->sreg1) {
+                               s390_lr   (code, ins->dreg, ins->sreg1);
+                       }
+                       s390_alr  (code, ins->dreg, ins->sreg2);
+                       EMIT_COND_SYSTEM_EXCEPTION (S390_CC_CY, "OverflowException");
+               }
+                       break;
+               case OP_ADD_OVF_CARRY: {
+                       if (ins->dreg != ins->sreg1) {
+                               s390_lr   (code, ins->dreg, ins->sreg1);
+                       }
+                       s390_lhi  (code, s390_r0, 0);
+                       s390_lr   (code, s390_r1, s390_r0);
+                       s390_alcr (code, s390_r0, s390_r1);
+                       s390_ar   (code, ins->dreg, ins->sreg2);
+                       EMIT_COND_SYSTEM_EXCEPTION (S390_CC_OV, "OverflowException");
+                       s390_ar   (code, ins->dreg, s390_r0);
+                       EMIT_COND_SYSTEM_EXCEPTION (S390_CC_OV, "OverflowException");
+               }
+                       break;
+               case OP_ADD_OVF_UN_CARRY: {
+                       if (ins->dreg != ins->sreg1) {
+                               s390_lr   (code, ins->dreg, ins->sreg1);
+                       }
+                       s390_alcr (code, ins->dreg, ins->sreg2);
+                       EMIT_COND_SYSTEM_EXCEPTION (S390_CC_CY, "OverflowException");
+               }
+                       break;
                case OP_SUBCC: {
                        if (ins->dreg != ins->sreg1) {
                                s390_lr   (code, ins->dreg, ins->sreg1);
                        }
-                       s390_sr (code, ins->dreg, ins->sreg2);
+                       s390_slr (code, ins->dreg, ins->sreg2);
                }
                        break;
                case CEE_SUB: {
@@ -3291,6 +3461,7 @@ guint8 cond;
                        s390_slbr (code, ins->dreg, ins->sreg2);
                }
                        break;
+               case OP_SUBCC_IMM:
                case OP_SUB_IMM: {
                        if (s390_is_imm16 (-ins->inst_imm)) {
                                if (ins->dreg != ins->sreg1) {
@@ -3315,6 +3486,43 @@ guint8 cond;
                        s390_sl   (code, ins->dreg, 0, s390_r13, 4);
                }
                        break;
+               case CEE_SUB_OVF: {
+                       if (ins->dreg != ins->sreg1) {
+                               s390_lr   (code, ins->dreg, ins->sreg1);
+                       }
+                       s390_sr   (code, ins->dreg, ins->sreg2);
+                       EMIT_COND_SYSTEM_EXCEPTION (S390_CC_OV, "OverflowException");
+               }
+                       break;
+               case CEE_SUB_OVF_UN: {
+                       if (ins->dreg != ins->sreg1) {
+                               s390_lr   (code, ins->dreg, ins->sreg1);
+                       }
+                       s390_slr  (code, ins->dreg, ins->sreg2);
+                       EMIT_COND_SYSTEM_EXCEPTION (S390_CC_NC, "OverflowException");
+               }
+                       break;
+               case OP_SUB_OVF_CARRY: {
+                       if (ins->dreg != ins->sreg1) {
+                               s390_lr   (code, ins->dreg, ins->sreg1);
+                       }
+                       s390_lhi  (code, s390_r0, 0);
+                       s390_lr   (code, s390_r1, s390_r0);
+                       s390_slbr (code, s390_r0, s390_r1);
+                       s390_sr   (code, ins->dreg, ins->sreg2);
+                       EMIT_COND_SYSTEM_EXCEPTION (S390_CC_OV, "OverflowException");
+                       s390_ar   (code, ins->dreg, s390_r0);
+                       EMIT_COND_SYSTEM_EXCEPTION (S390_CC_OV, "OverflowException");
+               }
+                       break;
+               case OP_SUB_OVF_UN_CARRY: {
+                       if (ins->dreg != ins->sreg1) {
+                               s390_lr   (code, ins->dreg, ins->sreg1);
+                       }
+                       s390_slbr (code, ins->dreg, ins->sreg2);
+                       EMIT_COND_SYSTEM_EXCEPTION (S390_CC_NC, "OverflowException");
+               }
+                       break;
                case CEE_AND: {
                        if (ins->sreg1 == ins->dreg) {
                                s390_nr   (code, ins->dreg, ins->sreg2);
@@ -3557,11 +3765,21 @@ guint8 cond;
                }
                        break;
                case CEE_MUL_OVF: {
-                       s390_lhi  (code, s390_r0, 0);
-                       s390_lr   (code, s390_r1, ins->sreg1);
-                       s390_mr   (code, s390_r0, ins->sreg2);
+                       short int *o[2];
+                       s390_ltr  (code, s390_r1, ins->sreg1);
+                       s390_jz   (code, 0); CODEPTR(code, o[0]);
+                       s390_ltr  (code, s390_r0, ins->sreg2);
+                       s390_jnz  (code, 6);
+                       s390_lhi  (code, s390_r1, 0);
+                       s390_j    (code, 0); CODEPTR(code, o[1]);
+                       s390_xr   (code, s390_r0, s390_r1);
+                       s390_msr  (code, s390_r1, ins->sreg2);
+                       s390_xr   (code, s390_r0, s390_r1);
+                       s390_srl  (code, s390_r0, 0, 31);
                        s390_ltr  (code, s390_r0, s390_r0);
                        EMIT_COND_SYSTEM_EXCEPTION (S390_CC_NZ, "OverflowException");
+                       PTRSLOT   (code, o[0]); 
+                       PTRSLOT   (code, o[1]);
                        s390_lr   (code, ins->dreg, s390_r1);
                }
                        break;
@@ -3638,19 +3856,63 @@ guint8 cond;
                        }
                }
                        break;
-               case OP_FCONV_TO_R4: {
+               case OP_S390_SETF4RET: {
                        s390_ledbr (code, ins->dreg, ins->sreg1);
                }
                        break;
-               case CEE_JMP:
-                       g_assert_not_reached ();
+               case OP_FCONV_TO_R4: {
+                       if ((ins->next) &&
+                           (ins->next->opcode != OP_STORER4_MEMBASE_REG))
+                               s390_ledbr (code, ins->dreg, ins->sreg1);
+               }
+                       break;
+               case CEE_JMP: {
+                       int fParm;
+                       if (cfg->method->save_lmf)
+                               code = restoreLMF(cfg, code);
+
+                       if (cfg->flags & MONO_CFG_HAS_TAIL) {
+                               s390_lm (code, s390_r2, s390_r5, STK_BASE, 
+                                        S390_PARM_SAVE_OFFSET);
+                               for (fParm = 0; fParm < 4; fParm++)
+                                       s390_ld (code, fParm, 0, STK_BASE,
+                                          S390_FLOAT_SAVE_OFFSET+fParm*sizeof(double));
+                       }
+
+                       code = backUpStackPtr(cfg, code);
+                       s390_l   (code, s390_r14, 0, STK_BASE, S390_RET_ADDR_OFFSET);
+                       mono_add_patch_info (cfg, code - cfg->native_code,
+                                            MONO_PATCH_INFO_METHOD_JUMP,
+                                            ins->inst_p0);
+                       s390_jcl (code, S390_CC_UN, 0);
+               }
                        break;
                case OP_CHECK_THIS: {
                        /* ensure ins->sreg1 is not NULL */
                        s390_icm (code, s390_r0, 15, ins->sreg1, 0);
                }
                        break;
-               case OP_FCALL:
+               case OP_ARGLIST: {
+                       NOT_IMPLEMENTED("OP_ARGLIST");
+                       s390_basr (code, s390_r13, 0);
+                       s390_j    (code, 4);
+                       s390_word (code, cfg->sig_cookie);
+                       s390_mvc  (code, 4, ins->sreg1, 0, s390_r13, 4);
+               }
+                       break;
+               case OP_FCALL: {
+                       call = (MonoCallInst*)ins;
+                       if (ins->flags & MONO_INST_HAS_METHOD)
+                               mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, 
+                                                    call->method);
+                       else
+                               mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, 
+                                                    call->fptr);
+                       s390_brasl (code, s390_r14, 0);
+                       if (call->signature->ret->type == MONO_TYPE_R4)
+                               s390_ldebr (code, s390_f0, s390_f0);
+               }
+                       break;
                case OP_LCALL:
                case OP_VCALL:
                case OP_VOIDCALL:
@@ -3663,7 +3925,14 @@ guint8 cond;
                        s390_brasl (code, s390_r14, 0);
                }
                        break;
-               case OP_FCALL_REG:
+               case OP_FCALL_REG: {
+                       call = (MonoCallInst*)ins;
+                       s390_lr   (code, s390_r1, ins->sreg1);
+                       s390_basr (code, s390_r14, s390_r1);
+                       if (call->signature->ret->type == MONO_TYPE_R4)
+                               s390_ldebr (code, s390_f0, s390_f0);
+               }
+                       break;
                case OP_LCALL_REG:
                case OP_VCALL_REG:
                case OP_VOIDCALL_REG:
@@ -3672,7 +3941,14 @@ guint8 cond;
                        s390_basr (code, s390_r14, s390_r1);
                }
                        break;
-               case OP_FCALL_MEMBASE:
+               case OP_FCALL_MEMBASE: {
+                       call = (MonoCallInst*)ins;
+                       s390_l    (code, s390_r1, 0, ins->sreg1, ins->inst_offset);
+                       s390_basr (code, s390_r14, s390_r1);
+                       if (call->signature->ret->type == MONO_TYPE_R4)
+                               s390_ldebr (code, s390_f0, s390_f0);
+               }
+                       break;
                case OP_LCALL_MEMBASE:
                case OP_VCALL_MEMBASE:
                case OP_VOIDCALL_MEMBASE:
@@ -3685,6 +3961,9 @@ guint8 cond;
                        g_assert_not_reached ();
                        break;
                case OP_LOCALLOC: {
+                       int alloca_skip = S390_MINIMAL_STACK_SIZE + cfg->param_area + 
+                                         S390_STACK_ALIGNMENT - 1;
+                       int area_offset = S390_ALIGN(alloca_skip, S390_STACK_ALIGNMENT);
                        s390_lr   (code, s390_r1, ins->sreg1);
                        s390_ahi  (code, s390_r1, 14);
                        s390_srl  (code, s390_r1, 0, 3);
@@ -3693,7 +3972,7 @@ guint8 cond;
                        s390_lcr  (code, s390_r1, s390_r1);
                        s390_la   (code, STK_BASE, STK_BASE, s390_r1, 0);
                        s390_st   (code, s390_r13, 0, STK_BASE, 0);
-                       s390_la   (code, ins->dreg, 0, STK_BASE, S390_MINIMAL_STACK_SIZE+7);
+                       s390_la   (code, ins->dreg, 0, STK_BASE, area_offset);
                        s390_srl  (code, ins->dreg, 0, 3);
                        s390_sll  (code, ins->dreg, 0, 3);
                }
@@ -3710,20 +3989,49 @@ guint8 cond;
                }
                        break;
                case OP_START_HANDLER: {
-                       s390_lr   (code, s390_r0, s390_r14);
-                       s390_st   (code, s390_r0, 0, ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
+                       if (s390_is_uimm12 (ins->inst_left->inst_offset)) {
+                               s390_st   (code, s390_r14, 0, 
+                                          ins->inst_left->inst_basereg, 
+                                          ins->inst_left->inst_offset);
+                       } else {
+                               s390_basr (code, s390_r13, 0);
+                               s390_j    (code, 4);
+                               s390_word (code, ins->inst_left->inst_offset);
+                               s390_l    (code, s390_r13, 0, s390_r13, 4);
+                               s390_st   (code, s390_r14, s390_r13, 
+                                          ins->inst_left->inst_basereg, 0);
+                       }
                }
                        break;
                case OP_ENDFILTER: {
                        if (ins->sreg1 != s390_r2)
                                s390_lr (code, s390_r2, ins->sreg1);
-                       s390_l   (code, STK_BASE, 0, STK_BASE, 0);
-                       s390_lm  (code, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
+                       if (s390_is_uimm12 (ins->inst_left->inst_offset)) {
+                               s390_l  (code, s390_r14, 0, ins->inst_left->inst_basereg,
+                                        ins->inst_left->inst_offset);
+                       } else {
+                               s390_basr (code, s390_r13, 0);
+                               s390_j    (code, 4);
+                               s390_word (code, ins->inst_left->inst_offset);
+                               s390_l    (code, s390_r13, 0, s390_r13, 4);
+                               s390_l    (code, s390_r14, s390_r13, 
+                                          ins->inst_left->inst_basereg, 0);
+                       }
                        s390_br  (code, s390_r14);
                }
                        break;
                case CEE_ENDFINALLY: {
-                       s390_l   (code, s390_r14, 0, ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
+                       if (s390_is_uimm12 (ins->inst_left->inst_offset)) {
+                               s390_l  (code, s390_r14, 0, ins->inst_left->inst_basereg,
+                                        ins->inst_left->inst_offset);
+                       } else {
+                               s390_basr (code, s390_r13, 0);
+                               s390_j    (code, 4);
+                               s390_word (code, ins->inst_left->inst_offset);
+                               s390_l    (code, s390_r13, 0, s390_r13, 4);
+                               s390_l    (code, s390_r14, s390_r13, 
+                                          ins->inst_left->inst_basereg, 0);
+                       }
                        s390_br  (code, s390_r14);
                }
                        break;
@@ -3846,14 +4154,13 @@ guint8 cond;
                        break;
                case OP_R4CONST: {
                        if (*((float *) ins->inst_p0) == 0) {
-                               s390_lzer (code, ins->dreg);
+                               s390_lzdr (code, ins->dreg);
                        } else {
                                s390_basr (code, s390_r13, 0);
                                s390_j    (code, 4);
                                s390_word (code, ins->inst_p0);
                                s390_l    (code, s390_r13, 0, s390_r13, 4);
-                               s390_le   (code, ins->dreg, 0, s390_r13, 0);
-                               s390_ldebr(code, ins->dreg, ins->dreg);
+                               s390_ldeb (code, ins->dreg, 0, s390_r13, 0);
                        }
                }
                        break;
@@ -3883,29 +4190,28 @@ guint8 cond;
                        break;
                case OP_STORER4_MEMBASE_REG: {
                        if (s390_is_uimm12(ins->inst_offset)) {
-                               s390_ledbr(code, s390_f0, ins->sreg1);
-                               s390_ste  (code, s390_f0, 0, ins->inst_destbasereg, ins->inst_offset);
+                               s390_ledbr(code, s390_f15, ins->sreg1);
+                               s390_ste  (code, s390_f15, 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_ledbr(code, s390_f0, ins->sreg1);
-                               s390_ste  (code, s390_f0, s390_r13, ins->inst_destbasereg, 0);
+                               s390_ledbr(code, s390_f15, ins->sreg1);
+                               s390_ste  (code, s390_f15, s390_r13, ins->inst_destbasereg, 0);
                        }
                }
                        break;
                case OP_LOADR4_MEMBASE: {
                        if (s390_is_uimm12(ins->inst_offset)) {
-                               s390_le   (code, ins->dreg, 0, ins->inst_basereg, ins->inst_offset);
+                               s390_ldeb (code, ins->dreg, 0, ins->inst_basereg, 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_le   (code, ins->dreg, s390_r13, ins->inst_basereg, 0);
+                               s390_ldeb (code, ins->dreg, s390_r13, ins->inst_basereg, 0);
                        }
-                       s390_ldebr (code, ins->dreg, ins->dreg);
                }
                        break;
                case CEE_CONV_R_UN: {
@@ -4110,15 +4416,47 @@ guint8 cond;
                        break;
                case CEE_CKFINITE: {
                        short *o;
-                       s390_lhi  (code, s390_r13, 0xfc0);
+                       s390_lhi  (code, s390_r13, 0x7f);
                        s390_tcdb (code, ins->sreg1, 0, s390_r13, 0);
                        s390_jz   (code, 0); CODEPTR(code, o);
-                       mono_add_patch_info (cfg, code - cfg->native_code + 2
+                       mono_add_patch_info (cfg, code - cfg->native_code, 
                                             MONO_PATCH_INFO_EXC, "ArithmeticException");
                        s390_brasl (code, s390_r14,0);
                        PTRSLOT(code, o);
                }
                        break;
+               case OP_S390_MOVE: {
+                       if (ins->unused > 0) {
+                               if (ins->unused <= 256) {
+                                       s390_mvc  (code, ins->unused, ins->dreg, 
+                                                  ins->inst_offset, ins->sreg1, ins->inst_imm);
+                               } else {
+                                       s390_lr   (code, s390_r0, ins->dreg);
+                                       if (s390_is_imm16 (ins->inst_offset)) {
+                                               s390_ahi  (code, s390_r0, ins->inst_offset);
+                                       } else {
+                                               s390_basr (code, s390_r13, 0);
+                                               s390_j    (code, 4);
+                                               s390_word (code, ins->inst_offset);
+                                               s390_a    (code, s390_r0, 0, s390_r13, 4);
+                                       }
+                                       s390_lr   (code, s390_r12, ins->sreg1);
+                                       if (s390_is_imm16 (ins->inst_imm)) {
+                                               s390_ahi  (code, s390_r12, ins->inst_imm);
+                                       } else {
+                                               s390_basr (code, s390_r13, 0);
+                                               s390_j    (code, 4);
+                                                       s390_word (code, ins->inst_imm);
+                                               s390_a    (code, s390_r12, 0, s390_r13, 4);
+                                       }
+                                       s390_lr   (code, s390_r1, ins->sreg1);
+                                       s390_lr   (code, s390_r13, s390_r1);
+                                       s390_mvcle(code, s390_r0, s390_r12, 0, 0);
+                                       s390_jo   (code, -2);
+                               }
+                       }
+               }
+                       break;
                default:
                        g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
                        g_assert_not_reached ();
@@ -4210,9 +4548,26 @@ mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, Mono
                        ip    += 2;     /* Skip over op-code */
                        break;
                }
-               case MONO_PATCH_INFO_METHOD_JUMP:
-                       g_assert_not_reached ();
+               case MONO_PATCH_INFO_METHOD_JUMP: {
+                       GSList *list;
+
+                       /*------------------------------------------------------*/
+                       /* get the trampoline to the method from the domain     */
+                       /*------------------------------------------------------*/
+                       target = mono_create_jump_trampoline (domain, 
+                                                     patch_info->data.method, 
+                                                     TRUE);
+                       target = S390_RELATIVE(target, ip);
+                       if (!domain->jump_target_hash)
+                               domain->jump_target_hash = g_hash_table_new (NULL, NULL);
+                       list = g_hash_table_lookup (domain->jump_target_hash, 
+                                                   patch_info->data.method);
+                       list = g_slist_prepend (list, ip);
+                       g_hash_table_insert (domain->jump_target_hash, 
+                                            patch_info->data.method, list);
+                       ip  +=2;
                        break;
+               }
                case MONO_PATCH_INFO_METHOD:
                        if (patch_info->data.method == method) {
                                target = S390_RELATIVE(code, ip);
@@ -4381,26 +4736,20 @@ mono_arch_emit_prolog (MonoCompile *cfg)
        cfg->code_size   = 256;
        cfg->native_code = code = g_malloc (cfg->code_size);
 
-       s390_stm  (code, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
+       if (cfg->flags & MONO_CFG_HAS_TAIL) {
+               s390_stm (code, s390_r2, s390_r14, STK_BASE, S390_PARM_SAVE_OFFSET);
+               for (pos = 0; pos < 4; pos++)
+                       s390_std (code, pos, 0, STK_BASE, 
+                                 S390_FLOAT_SAVE_OFFSET+pos*sizeof(double));
+       } else { 
+               s390_stm  (code, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
+        }
 
        if (cfg->flags & MONO_CFG_HAS_ALLOCA) {
                cfg->used_int_regs |= 1 << 11;
        }
 
        alloc_size = cfg->stack_offset;
-//     if (tracing)
-//             alloc_size += S390_TRACE_STACK_SIZE;
-//     pos = 0;
-       /* reserve room to save return value */
-//     if (tracing)
-//             pos += 8;
-
-//     alloc_size += pos;
-
-//     if (method->save_lmf) 
-//             alloc_size += sizeof(MonoLMF);
-
-//     alloc_size = S390_ALIGN(alloc_size, S390_STACK_ALIGNMENT);
 
        cfg->stack_usage = alloc_size;
        s390_lr   (code, s390_r11, STK_BASE);
@@ -4416,7 +4765,7 @@ mono_arch_emit_prolog (MonoCompile *cfg)
        }
        s390_st   (code, s390_r11, 0, STK_BASE, 0);
 
-       if (cfg->flags & MONO_CFG_HAS_ALLOCA)
+       if (cfg->frame_reg != STK_BASE)
                s390_lr (code, s390_r11, STK_BASE);
 
         /* compute max_offset in order to use short forward jumps
@@ -4458,10 +4807,12 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                        if (ainfo->regtype == RegTypeGeneral)
                                s390_lr (code, inst->dreg, ainfo->reg);
                        else if (ainfo->regtype == RegTypeFP) {
-                               if (ainfo->size == 4) {
-                                       s390_ledbr (code, inst->dreg, ainfo->reg);
-                               } else {
-                                       s390_ldr   (code, inst->dreg, ainfo->reg);
+                               if (inst->dreg != ainfo->reg) {
+                                       if (ainfo->size == 4) {
+                                               s390_ledbr (code, inst->dreg, ainfo->reg);
+                                       } else {
+                                               s390_ldr   (code, inst->dreg, ainfo->reg);
+                                       }
                                }
                        }
                        else if (ainfo->regtype == RegTypeBase) {
@@ -4533,8 +4884,20 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                                                break;
                                }
                        } else if (ainfo->regtype == RegTypeStructByAddr) {
-                               code = emit_memcpy (code, ainfo->vtsize, 
-                                                   inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
+                               if (ainfo->reg == STK_BASE) {
+                                       s390_lr  (code, s390_r13, ainfo->reg);
+                                       s390_ahi (code, s390_r13, alloc_size);
+                                       s390_l   (code, s390_r13, 0, s390_r13, 
+                                                 ainfo->offparm + S390_MINIMAL_STACK_SIZE);
+                                       code = emit_memcpy (code, abs(ainfo->vtsize), 
+                                                           inst->inst_basereg, 
+                                                           inst->inst_offset, s390_r13, 0);
+                               } else {
+                                       code = emit_memcpy (code, abs(ainfo->vtsize), 
+                                                           inst->inst_basereg, 
+                                                           inst->inst_offset, 
+                                                           ainfo->reg, 0);
+                               }
                        } else
                                g_assert_not_reached ();
                }
@@ -4599,7 +4962,6 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                /* save the current IP                                           */
                /*---------------------------------------------------------------*/
                s390_lr    (code, s390_r1, cfg->frame_reg);
-//             s390_ahi   (code, s390_r1, alloc_size);
                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);
@@ -4608,7 +4970,7 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                /*---------------------------------------------------------------*/
                /* Save general and floating point registers                     */
                /*---------------------------------------------------------------*/
-               s390_stm   (code, s390_r2, s390_r6, s390_r13, G_STRUCT_OFFSET(MonoLMF, gregs[2]));
+               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]));
                }
@@ -4648,7 +5010,7 @@ mono_arch_emit_epilog (MonoCompile *cfg)
        MonoMethod *method = cfg->method;
        MonoMethodSignature *sig = method->signature;
        MonoInst *inst;
-       int i, lmfOffset, tracing = 0;
+       int i, tracing = 0;
        guint8 *code;
 
        code = cfg->native_code + cfg->code_len;
@@ -4658,37 +5020,14 @@ mono_arch_emit_epilog (MonoCompile *cfg)
                tracing = 1;
        }
        
-       if (method->save_lmf) {
-               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);
-       }
+       if (method->save_lmf) 
+               code = restoreLMF(cfg, code);
 
-       if (cfg->frame_reg != STK_BASE)
-               s390_lr  (code, STK_BASE, cfg->frame_reg);
+       if (cfg->flags & MONO_CFG_HAS_ALLOCA) 
+               s390_l   (code, STK_BASE, 0, STK_BASE, 0);
+       else
+               code = backUpStackPtr(cfg, code);
 
-       s390_ahi (code, STK_BASE, cfg->stack_usage);
        s390_lm  (code, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
        s390_br  (code, s390_r14);
 
@@ -4852,6 +5191,17 @@ mono_arch_print_tree (MonoInst *tree, int arity)
                                mono_arch_regname (tree->inst_basereg));
                        done = 1;
                        break;
+               case OP_S390_MOVE:
+                       printf ("[0x%x(%d,%s),0x%x(%s)]",
+                               tree->inst_offset, tree->unused,
+                               tree->dreg, tree->inst_imm, 
+                               tree->sreg1);
+                       done = 1;
+                       break;
+               case OP_S390_SETF4RET:
+                       printf ("[f%d,f%d]", 
+                               mono_arch_regname (tree->dreg),
+                               mono_arch_regname (tree->sreg1));
                default:
                        done = 0;
        }
@@ -4881,3 +5231,13 @@ mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
 }
 
 /*========================= End of Function ========================*/
+
+MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
+{
+       return NULL;
+}
+
+MonoInst* mono_arch_get_thread_intrinsic (MonoCompile* cfg)
+{
+       return NULL;
+}