Merge pull request #5420 from nealef/z13v5
authorRodrigo Kumpera <kumpera@users.noreply.github.com>
Thu, 24 Aug 2017 20:58:08 +0000 (16:58 -0400)
committerGitHub <noreply@github.com>
Thu, 24 Aug 2017 20:58:08 +0000 (16:58 -0400)
Add support for z13 processor

1  2 
mono/mini/mini-s390x.c

diff --combined mono/mini/mini-s390x.c
index 28aa4dcb2d05fb371e5cae02737f766741bfd469,be09d4680a8d290519e1286a34b21e540f71bfa3..8e82dfa0ccabaccba02d16c6d25542d0895fb87d
@@@ -61,6 -61,69 +61,69 @@@ if (ins->inst_target_bb->native_offset
                s390_jcl (code, cond, 0);                               \
        } while (0); 
  
+ #define EMIT_COMP_AND_BRANCH(ins, cab, cmp)                                   \
+ {                                                                             \
+ if (ins->inst_true_bb->native_offset) {                                       \
+       int displace;                                                           \
+       displace = ((cfg->native_code +                                         \
+                   ins->inst_true_bb->native_offset) - code) / 2;              \
+       if (s390_is_imm16(displace)) {                                          \
+               s390_##cab (code, ins->sreg1, ins->sreg2,                       \
+                           ins->sreg3, displace);                              \
+       } else {                                                                \
+               s390_##cmp (code, ins->sreg1, ins->sreg2);                      \
+               displace = ((cfg->native_code +                                 \
+                           ins->inst_true_bb->native_offset) - code) / 2;      \
+               s390_jcl (code, ins->sreg3, displace);                          \
+       }                                                                       \
+ } else {                                                                      \
+       s390_##cmp (code, ins->sreg1, ins->sreg2);                              \
+       mono_add_patch_info (cfg, code - cfg->native_code,                      \
+                            MONO_PATCH_INFO_BB, ins->inst_true_bb);            \
+       s390_jcl (code, ins->sreg3, 0);                                         \
+ }                                                                             \
+ }
+ #define EMIT_COMP_AND_BRANCH_IMM(ins, cab, cmp, lat, logical)                 \
+ {                                                                             \
+ if (ins->inst_true_bb->native_offset) {                                       \
+       int displace;                                                           \
+       if ((ins->backend.data == 0) && (!logical)) {                           \
+               s390_##lat (code, ins->sreg1, ins->sreg1);                      \
+               displace = ((cfg->native_code +                                 \
+                           ins->inst_true_bb->native_offset) - code) / 2;      \
+               if (s390_is_imm16(displace)) {                                  \
+                       s390_brc (code, ins->sreg3, displace);                  \
+               } else {                                                        \
+                       s390_jcl (code, ins->sreg3, displace);                  \
+               }                                                               \
+       } else {                                                                \
+               S390_SET (code, s390_r0, ins->backend.data);                    \
+               displace = ((cfg->native_code +                                 \
+                           ins->inst_true_bb->native_offset) - code) / 2;      \
+               if (s390_is_imm16(displace)) {                                  \
+                       s390_##cab (code, ins->sreg1, s390_r0,                  \
+                                   ins->sreg3, displace);                      \
+               } else {                                                        \
+                       s390_##cmp (code, ins->sreg1, s390_r0);                 \
+                       displace = ((cfg->native_code +                         \
+                           ins->inst_true_bb->native_offset) - code) / 2;      \
+                       s390_jcl (code, ins->sreg3, displace);                  \
+               }                                                               \
+       }                                                                       \
+ } else {                                                                      \
+       if ((ins->backend.data == 0) && (!logical)) {                           \
+               s390_##lat (code, ins->sreg1, ins->sreg1);                      \
+       } else {                                                                \
+               S390_SET (code, s390_r0, ins->backend.data);                    \
+               s390_##cmp (code, ins->sreg1, s390_r0);                         \
+       }                                                                       \
+       mono_add_patch_info (cfg, code - cfg->native_code,                      \
+                            MONO_PATCH_INFO_BB, ins->inst_true_bb);            \
+       s390_jcl (code, ins->sreg3, 0);                                         \
+ }                                                                             \
+ }
  #define CHECK_SRCDST_COM                                              \
        if (ins->dreg == ins->sreg2) {                                  \
                src2 = ins->sreg1;                                      \
  #include <mono/utils/mono-mmap.h>
  #include <mono/utils/mono-hwcap.h>
  #include <mono/utils/mono-threads.h>
 +#include <mono/utils/unlocked.h>
  
  #include "mini-s390x.h"
  #include "cpu-s390x.h"
@@@ -379,6 -441,7 +442,7 @@@ static CallInfo * get_call_info (MonoCo
  static guchar * emit_float_to_int (MonoCompile *, guchar *, int, int, int, gboolean);
  static guint8 * emit_load_volatile_arguments (guint8 *, MonoCompile *);
  static __inline__ void emit_unwind_regs(MonoCompile *, guint8 *, int, int, long);
+ static void compare_and_branch(MonoBasicBlock *, MonoInst *, int, gboolean);
  
  /*========================= End of Prototypes ======================*/
  
  int mono_exc_esp_offset = 0;
  
  __thread int indent_level = 0;
+ __thread FILE *trFd = NULL;
+ int curThreadNo = 0;
  
  /*
   * The code generated for sequence points reads from this location, 
@@@ -647,9 -712,9 +713,9 @@@ indent (int diff) 
        if (diff < 0)
                indent_level += diff;
        v = indent_level;
-       printf("%p [%3d] ",(void *)pthread_self(),v);
+       fprintf (trFd, "%p [%3d] ",(void *)pthread_self(),v);
        while (v-- > 0) {
-               printf (". ");
+               fprintf (trFd, ". ");
        }
        if (diff > 0) 
                indent_level += diff;
@@@ -750,9 -815,9 +816,9 @@@ cvtMonoType(MonoTypeEnum t
  
  /*------------------------------------------------------------------*/
  /*                                                                  */
- /* Name               - decodeParm                                        */
+ /* Name               - decodeParmString                                  */
  /*                                                                  */
- /* Function   - Decode a parameter for the trace.                 */
+ /* Function   - Decode a parameter string for the trace.          */
  /*                                                                */
  /*------------------------------------------------------------------*/
  
@@@ -762,57 -827,68 +828,68 @@@ decodeParmString (MonoString *s
        MonoError error;
        char *str = mono_string_to_utf8_checked(s, &error);
        if (is_ok (&error))  {
-               printf("[STRING:%p:%s], ", s, str);
+               fprintf (trFd, "[STRING:%p:%s], ", s, str);
                g_free (str);
        } else {
                mono_error_cleanup (&error);
-               printf("[STRING:%p:], ", s);
+               fprintf (trFd, "[STRING:%p:], ", s);
        }
  }
  
+ /*========================= End of Function ========================*/
+ /*------------------------------------------------------------------*/
+ /*                                                                  */
+ /* Name               - decodeParm                                        */
+ /*                                                                  */
+ /* Function   - Decode a parameter for the trace.                 */
+ /*                                                                */
+ /*------------------------------------------------------------------*/
  static void 
  decodeParm(MonoType *type, void *curParm, int size)
  {
        guint32 simpleType;
  
        if (type->byref) {
-               printf("[BYREF:%p], ", *((char **) curParm));
+               fprintf (trFd, "[BYREF:%p], ", *((char **) curParm));
        } else {
                simpleType = mini_get_underlying_type(type)->type;
  enum_parmtype:
                switch (simpleType) {
                        case MONO_TYPE_I :
-                               printf ("[INTPTR:%p], ", *((int **) curParm));
+                               fprintf (trFd, "[INTPTR:%p], ", *((int **) curParm));
                                break;
                        case MONO_TYPE_U :
-                               printf ("[UINTPTR:%p], ", *((int **) curParm));
+                               fprintf (trFd, "[UINTPTR:%p], ", *((int **) curParm));
                                break;
                        case MONO_TYPE_BOOLEAN :
-                               printf ("[BOOL:%ld], ", *((gint64 *) curParm));
+                               fprintf (trFd, "[BOOL:%ld], ", *((gint64 *) curParm));
                                break;
                        case MONO_TYPE_CHAR :
-                               printf ("[CHAR:%c], ", *((int  *) curParm));
+                               fprintf (trFd, "[CHAR:%c], ", *((int  *) curParm));
                                break;
                        case MONO_TYPE_I1 :
-                               printf ("[INT1:%ld], ", *((gint64 *) curParm));
+                               fprintf (trFd, "[INT1:%ld], ", *((gint64 *) curParm));
                                break; 
                        case MONO_TYPE_I2 :
-                               printf ("[INT2:%ld], ", *((gint64 *) curParm));
+                               fprintf (trFd, "[INT2:%ld], ", *((gint64 *) curParm));
                                break; 
                        case MONO_TYPE_I4 :
-                               printf ("[INT4:%ld], ", *((gint64 *) curParm));
+                               fprintf (trFd, "[INT4:%ld], ", *((gint64 *) curParm));
                                break; 
                        case MONO_TYPE_U1 :
-                               printf ("[UINT1:%lu], ", *((guint64 *) curParm));
+                               fprintf (trFd, "[UINT1:%lu], ", *((guint64 *) curParm));
                                break; 
                        case MONO_TYPE_U2 :
-                               printf ("[UINT2:%lu], ", *((guint64 *) curParm));
+                               fprintf (trFd, "[UINT2:%lu], ", *((guint64 *) curParm));
                                break; 
                        case MONO_TYPE_U4 :
-                               printf ("[UINT4:%lu], ", *((guint64 *) curParm));
+                               fprintf (trFd, "[UINT4:%lu], ", *((guint64 *) curParm));
                                break; 
                        case MONO_TYPE_U8 :
-                               printf ("[UINT8:%lu], ", *((guint64 *) curParm));
+                               fprintf (trFd, "[UINT8:%lu], ", *((guint64 *) curParm));
                                break; 
                        case MONO_TYPE_STRING : {
                                MonoString *s = *((MonoString **) curParm);
                                        g_assert (((MonoObject *) s)->vtable->klass == mono_defaults.string_class);
                                        decodeParmString (s);
                                } else {
-                                       printf("[STRING:null], ");
+                                       fprintf (trFd, "[STRING:null], ");
                                }
                                break;
                        }
                                MonoObject *obj = *((MonoObject **) curParm);
                                MonoClass *klass;
                                if ((obj) && (obj->vtable)) {
-                                       printf("[CLASS/OBJ:");
+                                       fprintf (trFd, "[CLASS/OBJ:");
                                        klass = obj->vtable->klass;
-                                       printf("%p [%p] ",obj,curParm);
+                                       fprintf (trFd, "%p [%p] ",obj,curParm);
                                        if (klass == mono_defaults.string_class) {
                                                decodeParmString ((MonoString *)obj);
                                        } else if (klass == mono_defaults.int32_class) { 
-                                               printf("[INT32:%p:%d]", 
+                                               fprintf (trFd, "[INT32:%p:%d]", 
                                                        obj, *(gint32 *)((char *)obj + sizeof (MonoObject)));
                                        } else
-                                               printf("[%s.%s:%p]", 
+                                               fprintf (trFd, "[%s.%s:%p]", 
                                                       klass->name_space, klass->name, obj);
-                                       printf("], ");
+                                       fprintf (trFd, "], ");
                                } else {
-                                       printf("[OBJECT:null], ");
+                                       fprintf (trFd, "[OBJECT:null], ");
                                }
                                break;
                        }
                        case MONO_TYPE_PTR :
-                               printf("[PTR:%p], ", *((gpointer **) (curParm)));
+                               fprintf (trFd, "[PTR:%p], ", *((gpointer **) (curParm)));
                                break;
                        case MONO_TYPE_FNPTR :
-                               printf("[FNPTR:%p], ", *((gpointer **) (curParm)));
+                               fprintf (trFd, "[FNPTR:%p], ", *((gpointer **) (curParm)));
                                break;
                        case MONO_TYPE_ARRAY :
-                               printf("[ARRAY:%p], ", *((gpointer **) (curParm)));
+                               fprintf (trFd, "[ARRAY:%p], ", *((gpointer **) (curParm)));
                                break;
                        case MONO_TYPE_SZARRAY :
-                               printf("[SZARRAY:%p], ", *((gpointer **) (curParm)));
+                               fprintf (trFd, "[SZARRAY:%p], ", *((gpointer **) (curParm)));
                                break;
                        case MONO_TYPE_I8 :
-                               printf("[INT8:%ld], ", *((gint64 *) (curParm)));
+                               fprintf (trFd, "[INT8:%ld], ", *((gint64 *) (curParm)));
                                break;
                        case MONO_TYPE_R4 :
-                               printf("[FLOAT4:%g], ", *((float *) (curParm)));
+                               fprintf (trFd, "[FLOAT4:%g], ", *((float *) (curParm)));
                                break;
                        case MONO_TYPE_R8 :
-                               printf("[FLOAT8:%g], ", *((double *) (curParm)));
+                               fprintf (trFd, "[FLOAT8:%g], ", *((double *) (curParm)));
                                break;
                        case MONO_TYPE_VALUETYPE : {
                                int i;
  
                                if (type->data.klass->enumtype) {
                                        simpleType = mono_class_enum_basetype (type->data.klass)->type;
-                                       printf("{VALUETYPE} - ");
+                                       fprintf (trFd, "{VALUETYPE} - ");
                                        goto enum_parmtype;
                                }
  
                                if ((info->native_size == sizeof(float)) &&
                                    (info->num_fields  == 1) &&
                                    (info->fields[0].field->type->type == MONO_TYPE_R4)) {
-                                               printf("[FLOAT4:%f], ", *((float *) (curParm)));
+                                               fprintf (trFd, "[FLOAT4:%f], ", *((float *) (curParm)));
                                        break;
                                }
  
                                if ((info->native_size == sizeof(double)) &&
                                    (info->num_fields  == 1) &&
                                    (info->fields[0].field->type->type == MONO_TYPE_R8)) {
-                                       printf("[FLOAT8:%g], ", *((double *) (curParm)));
+                                       fprintf (trFd, "[FLOAT8:%g], ", *((double *) (curParm)));
                                        break;
                                }
  
-                               printf("[VALUETYPE:");
+                               fprintf (trFd, "[VALUETYPE:");
                                for (i = 0; i < size; i++)
-                                       printf("%02x,", *((guint8 *)curParm+i));
-                               printf("], ");
+                                       fprintf (trFd, "%02x,", *((guint8 *)curParm+i));
+                               fprintf (trFd, "], ");
                                break;
                        }
                        case MONO_TYPE_TYPEDBYREF: {
                                int i;
-                               printf("[TYPEDBYREF:");
+                               fprintf (trFd, "[TYPEDBYREF:");
                                for (i = 0; i < size; i++)
-                                       printf("%02x,", *((guint8 *)curParm+i));
-                               printf("]");
+                                       fprintf (trFd, "%02x,", *((guint8 *)curParm+i));
+                               fprintf (trFd, "]");
                                break;
                        }
                        default :
-                               printf("[%s], ",cvtMonoType(simpleType));
+                               fprintf (trFd, "[%s], ",cvtMonoType(simpleType));
                }
        }
  }
@@@ -937,13 -1013,18 +1014,18 @@@ enter_method (MonoMethod *method, RegPa
        ArgInfo *ainfo;
        void *curParm;
  
+       if (trFd == NULL) {
+               char buf[32];
+               sprintf(buf, "/tmp/mono.%d.trc.%d", getpid(), curThreadNo++);
+               trFd = fopen(buf, "w");
+       }
        fname = mono_method_full_name (method, TRUE);
        indent (1);
-       printf ("ENTER: %s ", fname);
+       fprintf (trFd, "ENTER: %s ", fname);
        g_free (fname);
  
        ip  = (*(guint64 *) (sp+S390_RET_ADDR_OFFSET));
-       printf ("ip: %p sp: %p - ", (gpointer) ip, sp); 
+       fprintf (trFd, "ip: %p sp: %p - ", (gpointer) ip, sp); 
  
        if (rParm == NULL)
                return;
        cinfo = get_call_info (NULL, NULL, sig);
  
        if (cinfo->struct_ret) {
-               printf ("[STRUCTRET:%p], ", (gpointer) rParm->gr[0]);
+               fprintf (trFd, "[STRUCTRET:%p], ", (gpointer) rParm->gr[0]);
                iParm = 1;
        }
  
                case MONO_TYPE_VALUETYPE:
                        if (obj) {
                                guint64 *value = (guint64 *) ((uintptr_t)this_arg + sizeof(MonoObject));
-                               printf("this:[value:%p:%016lx], ", this_arg, *value);
+                               fprintf (trFd, "this:[value:%p:%016lx], ", this_arg, *value);
                        } else 
-                               printf ("this:[NULL], ");
+                               fprintf (trFd, "this:[NULL], ");
                        break;
                case MONO_TYPE_STRING:
                        if (obj) {
                                if (obj->vtable) {
                                        klass = obj->vtable->klass;
                                        if (klass == mono_defaults.string_class) {
-                                               printf ("this:");
+                                               fprintf (trFd, "this:");
                                                decodeParmString((MonoString *)obj);
                                        } else {
-                                               printf ("this:%p[%s.%s], ", 
+                                               fprintf (trFd, "this:%p[%s.%s], ", 
                                                        obj, klass->name_space, klass->name);
                                        }
                                } else 
-                                       printf("vtable:[NULL], ");
+                                       fprintf (trFd, "vtable:[NULL], ");
                        } else 
-                               printf ("this:[NULL], ");
+                               fprintf (trFd, "this:[NULL], ");
                        break;
                default :
-                       printf("this[%s]: %p, ",cvtMonoType(method->klass->this_arg.type),this_arg);
+                       fprintf (trFd, "this[%s]: %p, ",cvtMonoType(method->klass->this_arg.type),this_arg);
                }
                oParm++;
        }
                                break;
                                
                        default :
-                               printf("???, ");
+                               fprintf (trFd, "???, ");
                }
        }       
-       printf("\n");
+       fprintf (trFd, "\n");
        g_free(cinfo);
  }
  
@@@ -1060,7 -1141,7 +1142,7 @@@ leave_method (MonoMethod *method, ...
  
        fname = mono_method_full_name (method, TRUE);
        indent (-1);
-       printf ("LEAVE: %s", fname);
+       fprintf (trFd, "LEAVE: %s", fname);
        g_free (fname);
  
        type = mono_method_signature (method)->ret;
@@@ -1072,57 -1153,57 +1154,57 @@@ handle_enum
        case MONO_TYPE_BOOLEAN: {
                int val = va_arg (ap, int);
                if (val)
-                       printf ("[TRUE:%d]", val);
+                       fprintf (trFd, "[TRUE:%d]", val);
                else 
-                       printf ("[FALSE]");
+                       fprintf (trFd, "[FALSE]");
                        
                break;
        }
        case MONO_TYPE_CHAR: {
                int val = va_arg (ap, int);
-               printf ("[CHAR:%d]", val);
+               fprintf (trFd, "[CHAR:%d]", val);
                break;
        }
        case MONO_TYPE_I1: {
                int val = va_arg (ap, int);
-               printf ("[INT1:%d]", val);
+               fprintf (trFd, "[INT1:%d]", val);
                break;
        }
        case MONO_TYPE_U1: {
                int val = va_arg (ap, int);
-               printf ("[UINT1:%d]", val);
+               fprintf (trFd, "[UINT1:%d]", val);
                break;
        }
        case MONO_TYPE_I2: {
                int val = va_arg (ap, int);
-               printf ("[INT2:%d]", val);
+               fprintf (trFd, "[INT2:%d]", val);
                break;
        }
        case MONO_TYPE_U2: {
                int val = va_arg (ap, int);
-               printf ("[UINT2:%d]", val);
+               fprintf (trFd, "[UINT2:%d]", val);
                break;
        }
        case MONO_TYPE_I4: {
                int val = va_arg (ap, int);
-               printf ("[INT4:%d]", val);
+               fprintf (trFd, "[INT4:%d]", val);
                break;
        }
        case MONO_TYPE_U4: {
                int val = va_arg (ap, int);
-               printf ("[UINT4:%d]", val);
+               fprintf (trFd, "[UINT4:%d]", val);
                break;
        }
        case MONO_TYPE_I: {
                gint64 val = va_arg (ap, gint64);
-               printf ("[INT:%ld]", val);
-               printf("]");
+               fprintf (trFd, "[INT:%ld]", val);
+               fprintf (trFd, "]");
                break;
        }
        case MONO_TYPE_U: {
                gint64 val = va_arg (ap, gint64);
-               printf ("[UINT:%lu]", val);
-               printf("]");
+               fprintf (trFd, "[UINT:%lu]", val);
+               fprintf (trFd, "]");
                break;
        }
        case MONO_TYPE_STRING: {
                        g_assert (((MonoObject *)s)->vtable->klass == mono_defaults.string_class);
                        decodeParmString (s);
                } else 
-                       printf ("[STRING:null], ");
+                       fprintf (trFd, "[STRING:null], ");
                break;
        }
        case MONO_TYPE_CLASS: 
  
                if ((o) && (o->vtable)) {
                        if (o->vtable->klass == mono_defaults.boolean_class) {
-                               printf ("[BOOLEAN:%p:%d]", o, *((guint8 *)o + sizeof (MonoObject)));            
+                               fprintf (trFd, "[BOOLEAN:%p:%d]", o, *((guint8 *)o + sizeof (MonoObject)));             
                        } else if  (o->vtable->klass == mono_defaults.int32_class) {
-                               printf ("[INT32:%p:%d]", o, *((gint32 *)((char *)o + sizeof (MonoObject))));    
+                               fprintf (trFd, "[INT32:%p:%d]", o, *((gint32 *)((char *)o + sizeof (MonoObject))));     
                        } else if  (o->vtable->klass == mono_defaults.int64_class) {
-                               printf ("[INT64:%p:%ld]", o, *((gint64 *)((char *)o + sizeof (MonoObject))));   
+                               fprintf (trFd, "[INT64:%p:%ld]", o, *((gint64 *)((char *)o + sizeof (MonoObject))));    
                        } else
-                               printf ("[%s.%s:%p]", o->vtable->klass->name_space, o->vtable->klass->name, o);
+                               fprintf (trFd, "[%s.%s:%p]", o->vtable->klass->name_space, o->vtable->klass->name, o);
                } else
-                       printf ("[OBJECT:%p]", o);
+                       fprintf (trFd, "[OBJECT:%p]", o);
               
                break;
        }
        case MONO_TYPE_ARRAY:
        case MONO_TYPE_SZARRAY: {
                gpointer p = va_arg (ap, gpointer);
-               printf ("[result=%p]", p);
+               fprintf (trFd, "[result=%p]", p);
                break;
        }
        case MONO_TYPE_I8: {
                gint64 l =  va_arg (ap, gint64);
-               printf ("[LONG:%ld]", l);
+               fprintf (trFd, "[LONG:%ld]", l);
                break;
        }
        case MONO_TYPE_U8: {
                guint64 l =  va_arg (ap, guint64);
-               printf ("[ULONG:%lu]", l);
+               fprintf (trFd, "[ULONG:%lu]", l);
                break;
        }
        case MONO_TYPE_R4: {
                double f = va_arg (ap, double);
-               printf ("[FLOAT4:%g]\n", f);
+               fprintf (trFd, "[FLOAT4:%g]\n", f);
                break;
        }
        case MONO_TYPE_R8: {
                double f = va_arg (ap, double);
-               printf ("[FLOAT8:%g]\n", f);
+               fprintf (trFd, "[FLOAT8:%g]\n", f);
                break;
        }
        case MONO_TYPE_VALUETYPE: {
                            (info->num_fields  == 1) &&
                            (info->fields[0].field->type->type == MONO_TYPE_R4)) {
                                double f = va_arg (ap, double);
-                               printf("[FLOAT4:%g]\n", (double) f);
+                               fprintf (trFd, "[FLOAT4:%g]\n", (double) f);
                                break;
                        }
  
                            (info->num_fields  == 1) &&
                            (info->fields[0].field->type->type == MONO_TYPE_R8)) {
                                double f = va_arg (ap, double);
-                               printf("[FLOAT8:%g]\n", f);
+                               fprintf (trFd, "[FLOAT8:%g]\n", f);
                                break;
                        }
  
                        switch (size) {
                                case 1: {
                                        guint32 p = va_arg (ap, guint32);
-                                       printf ("[%02x]\n",p);
+                                       fprintf (trFd, "[%02x]\n",p);
                                        break;
                                }
                                case 2: {
                                        guint32 p = va_arg (ap, guint32);
-                                       printf ("[%04x]\n",p);
+                                       fprintf (trFd, "[%04x]\n",p);
                                        break;
                                }
                                case 4: {
                                        guint32 p = va_arg (ap, guint32);
-                                       printf ("[%08x]\n",p);
+                                       fprintf (trFd, "[%08x]\n",p);
                                        break;
                                }
                                case 8: {
                                        guint64 p = va_arg (ap, guint64);
-                                       printf ("[%016lx]\n",p);
+                                       fprintf (trFd, "[%016lx]\n",p);
                                        break;
                                }
                                default: {
                                        gpointer p = va_arg (ap, gpointer);
-                                       printf ("[VALUETYPE] %p\n",p);
+                                       fprintf (trFd, "[VALUETYPE] %p\n",p);
                                }
                        }
                }
                case 2:
                case 4:
                case 8:
-                       printf ("[");
+                       fprintf (trFd, "[");
                        for (j = 0; p && j < size; j++)
-                               printf ("%02x,", p [j]);
-                       printf ("]\n");
+                               fprintf (trFd, "%02x,", p [j]);
+                       fprintf (trFd, "]\n");
                        break;
                default:
-                       printf ("[TYPEDBYREF]\n");
+                       fprintf (trFd, "[TYPEDBYREF]\n");
                }
        }
                break;
        case MONO_TYPE_GENERICINST: {
-               printf("[GENERICINST]\n");
+               fprintf (trFd, "[GENERICINST]\n");
        }
                break;
        case MONO_TYPE_MVAR: {
-               printf("[MVAR]\n");
+               fprintf (trFd, "[MVAR]\n");
        }
                break;
        case MONO_TYPE_CMOD_REQD: {
-               printf("[CMOD_REQD]\n");
+               fprintf (trFd, "[CMOD_REQD]\n");
        }
                break;
        case MONO_TYPE_CMOD_OPT: {
-               printf("[CMOD_OPT]\n");
+               fprintf (trFd, "[CMOD_OPT]\n");
        }
                break;
        case MONO_TYPE_INTERNAL: {
-               printf("[INTERNAL]\n");
+               fprintf (trFd, "[INTERNAL]\n");
        }
                break;
        default:
-               printf ("(unknown return type %x)", 
+               fprintf (trFd, "(unknown return type %x)", 
                        mono_method_signature (method)->ret->type);
        }
  
        ip = ((gint64) __builtin_extract_return_addr (__builtin_return_address (0)));
-       printf (" ip: %p\n", (gpointer) ip);
+       fprintf (trFd, " ip: %p\n", (gpointer) ip);
        va_end (ap);
  }
  
@@@ -1456,7 -1537,9 +1538,9 @@@ mono_arch_get_global_int_regs (MonoComp
        /* FIXME: s390_r12 is reserved for bkchain_reg. Only reserve it if needed */
        top = 12;
        for (i = 8; i < top; ++i) {
-               if (cfg->frame_reg != i)
+               if ((cfg->frame_reg != i) && 
+                   //!((cfg->uses_rgctx_reg) && (i == MONO_ARCH_IMT_REG)))
+                   (i != MONO_ARCH_IMT_REG))
                        regs = g_list_prepend (regs, GUINT_TO_POINTER (i));
        }
  
@@@ -1990,10 -2073,7 +2074,7 @@@ mono_arch_allocate_vars (MonoCompile *c
        cfg->arch.bkchain_reg = -1;
  
        if (frame_reg != STK_BASE) 
-               cfg->used_int_regs |= (1 << frame_reg);         
-       if (cfg->uses_rgctx_reg)
-               cfg->used_int_regs |= (1 << MONO_ARCH_IMT_REG);
+               cfg->used_int_regs |= (1LL << frame_reg);               
  
        sig     = mono_method_signature (cfg->method);
        
                                }
                                break;
                        }
- #if 0
-                       if ((sig->call_convention == MONO_CALL_VARARG) && 
-                           (cinfo->args[iParm].regtype != RegTypeGeneral) &&
-                           (iParm < sig->sentinelpos)) 
-                               cfg->sig_cookie += size;
- printf("%s %4d cookine %x\n",__FUNCTION__,__LINE__,cfg->sig_cookie);
- #endif
                        offset += MAX(size, 8);
                }
                curinst++;
@@@ -2474,27 -2546,6 +2547,6 @@@ mono_arch_emit_call (MonoCompile *cfg, 
                                ins->inst_destbasereg = STK_BASE;
                                ins->inst_offset = ainfo->offset;
                                ins->sreg1 = in->dreg;
- #if 0
-                               /* This is needed by MonoTypedRef->value to point to the correct data */
-                               if ((sig->call_convention == MONO_CALL_VARARG) &&
-                                       (i >= sig->sentinelpos)) {
-                                       switch (ainfo->size) {
-                                       case 1:
-                                               ins->opcode = OP_STOREI1_MEMBASE_REG;
-                                               break;
-                                       case 2:
-                                               ins->opcode = OP_STOREI2_MEMBASE_REG;
-                                               break;
-                                       case 4:
-                                               ins->opcode = OP_STOREI4_MEMBASE_REG;
-                                               break;
-                                       default:
-                                               break;
-                                       }
-                               }
- #endif
                                MONO_ADD_INS (cfg->cbb, ins);
                        }
                        break;
@@@ -2789,6 -2840,64 +2841,64 @@@ handle_enum
  
  /*========================= End of Function ========================*/
  
+ /*------------------------------------------------------------------*/
+ /*                                                                  */
+ /* Name               - compare_and_branch                                */
+ /*                                                                  */
+ /* Function   - Form a peephole pass at the code looking for      */
+ /*              simple optimizations.                             */
+ /*                                                                */
+ /*------------------------------------------------------------------*/
+ static void
+ compare_and_branch(MonoBasicBlock *bb, MonoInst *ins, int cc, gboolean logical)
+ {
+       MonoInst *last;
+       if (mono_hwcap_s390x_has_gie) {
+               last = mono_inst_prev (ins, FILTER_IL_SEQ_POINT);
+               ins->sreg1 = last->sreg1;
+               ins->sreg2 = last->sreg2;
+               ins->sreg3 = cc;
+               switch(last->opcode) {
+               case OP_ICOMPARE:
+                       if (logical)
+                               ins->opcode = OP_S390_CLRJ;
+                       else
+                               ins->opcode = OP_S390_CRJ;
+                       MONO_DELETE_INS(bb, last);
+                       break;
+               case OP_COMPARE:
+               case OP_LCOMPARE:
+                       if (logical)
+                               ins->opcode = OP_S390_CLGRJ;
+                       else
+                               ins->opcode = OP_S390_CGRJ;
+                       MONO_DELETE_INS(bb, last);
+                       break;
+               case OP_ICOMPARE_IMM:
+                       ins->backend.data = (gpointer) last->inst_imm;
+                       if (logical)
+                               ins->opcode = OP_S390_CLIJ;
+                       else
+                               ins->opcode = OP_S390_CIJ;
+                       MONO_DELETE_INS(bb, last);
+                       break;
+               case OP_COMPARE_IMM:
+               case OP_LCOMPARE_IMM:
+                       ins->backend.data = (gpointer) last->inst_imm;
+                       if (logical)
+                               ins->opcode = OP_S390_CLGIJ;
+                       else
+                               ins->opcode = OP_S390_CGIJ;
+                       MONO_DELETE_INS(bb, last);
+                       break;
+               }
+       }
+ }
+ /*========================= End of Function ========================*/
  /*------------------------------------------------------------------*/
  /*                                                                  */
  /* Name               - mono_arch_peephole_pass_1                         */
  void
  mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
  {
+       MonoInst *ins, *n;
+       MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
+               switch (ins->opcode) {
+               case OP_IBEQ:
+               case OP_LBEQ:
+                       compare_and_branch(bb, ins, S390_CC_EQ, FALSE);
+                       break;
+               case OP_LBNE_UN:
+               case OP_IBNE_UN:
+                       compare_and_branch(bb, ins, S390_CC_NE, TRUE);
+                       break;
+               case OP_LBLT:
+               case OP_IBLT:
+                       compare_and_branch(bb, ins, S390_CC_LT, FALSE);
+                       break;
+               case OP_LBLT_UN:
+               case OP_IBLT_UN:
+                       compare_and_branch(bb, ins, S390_CC_LT, TRUE);
+                       break;
+               case OP_LBGT:
+               case OP_IBGT:
+                       compare_and_branch(bb, ins, S390_CC_GT, FALSE);
+                       break;
+               case OP_LBGT_UN:
+               case OP_IBGT_UN:
+                       compare_and_branch(bb, ins, S390_CC_GT, TRUE);
+                       break;
+               case OP_LBGE:
+               case OP_IBGE:
+                       compare_and_branch(bb, ins, S390_CC_GE, FALSE);
+                       break;
+               case OP_LBGE_UN:
+               case OP_IBGE_UN:
+                       compare_and_branch(bb, ins, S390_CC_GE, TRUE);
+                       break;
+               case OP_LBLE:
+               case OP_IBLE:
+                       compare_and_branch(bb, ins, S390_CC_LE, FALSE);
+                       break;
+               case OP_LBLE_UN:
+               case OP_IBLE_UN:
+                       compare_and_branch(bb, ins, S390_CC_LE, TRUE);
+                       break;
+               // default:
+               //      mono_peephole_ins (bb, ins);
+               }
+       }
  }
  
  /*========================= End of Function ========================*/
  void
  mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
  {
-       MonoInst *ins, *n;
+       MonoInst *ins, *n, *last_ins = NULL;
  
        MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
+               switch (ins->opcode) {
+               case OP_LOADU4_MEMBASE:
+               case OP_LOADI4_MEMBASE:
+                       if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG) &&
+                                       ins->inst_basereg == last_ins->inst_destbasereg &&
+                                       ins->inst_offset == last_ins->inst_offset) {
+                               ins->opcode = (ins->opcode == OP_LOADI4_MEMBASE) ? OP_ICONV_TO_I4 : OP_ICONV_TO_U4;
+                               ins->sreg1 = last_ins->sreg1;
+                       }
+                       break;
+               }
                mono_peephole_ins (bb, ins);
        }
  }
@@@ -2930,15 -3099,15 +3100,15 @@@ emit_float_to_int (MonoCompile *cfg, gu
  
  /*------------------------------------------------------------------*/
  /*                                                                  */
- /* Name               - gboolean_is_unsigned.                             */
+ /* Name               - is_unsigned.                                      */
  /*                                                                  */
  /* Function   - Return TRUE if next opcode is checking for un-    */
  /*              signed value.                                     */
  /*                                                                */
  /*------------------------------------------------------------------*/
  
- static 
gboolean is_unsigned (MonoInst *next)
+ static gboolean 
+ is_unsigned (MonoInst *next)
  {
        if ((next) && 
                (((next->opcode >= OP_IBNE_UN) &&
                 ((next->opcode >= OP_COND_EXC_INE_UN) &&
                  (next->opcode <= OP_COND_EXC_ILT_UN)) ||
                 ((next->opcode == OP_CLT_UN) ||
-                 (next->opcode == OP_CGT_UN)) ||
+                 (next->opcode == OP_CGT_UN) ||
+                 (next->opcode == OP_ICGE_UN)  ||
+                 (next->opcode == OP_ICLE_UN)) ||
                 ((next->opcode == OP_ICLT_UN) ||
                  (next->opcode == OP_ICGT_UN) ||
                  (next->opcode == OP_LCLT_UN) ||
@@@ -3117,6 -3288,14 +3289,14 @@@ mono_arch_output_basic_block (MonoCompi
                        s390_llghr (code, ins->dreg, ins->sreg1);
                }
                        break;
+               case OP_ICONV_TO_U4: {
+                       s390_llgfr (code, ins->dreg, ins->sreg1);
+               }
+                       break;
+               case OP_ICONV_TO_I4: {
+                       s390_lgfr (code, ins->dreg, ins->sreg1);
+               }
+                       break;
                case OP_COMPARE: 
                case OP_LCOMPARE: {
                        if (is_unsigned (ins->next))
                        break;
                case OP_COMPARE_IMM:
                case OP_LCOMPARE_IMM: {
-                       S390_SET (code, s390_r0, ins->inst_imm);
-                       if (is_unsigned (ins->next))
-                               s390_clgr (code, ins->sreg1, s390_r0);
-                       else
-                               s390_cgr  (code, ins->sreg1, s390_r0);
+                       gboolean branchUn = is_unsigned (ins->next);
+                       if ((ins->inst_imm == 0) && (!branchUn)) {
+                               s390_ltgr (code, ins->sreg1, ins->sreg1);
+                       } else {
+                               S390_SET (code, s390_r0, ins->inst_imm);
+                               if (branchUn)
+                                       s390_clgr (code, ins->sreg1, s390_r0);
+                               else
+                                       s390_cgr  (code, ins->sreg1, s390_r0);
+                       }
                }
                        break;
                case OP_ICOMPARE_IMM: {
-                       S390_SET (code, s390_r0, ins->inst_imm);
-                       if (is_unsigned (ins->next))
-                               s390_clr  (code, ins->sreg1, s390_r0);
-                       else
-                               s390_cr   (code, ins->sreg1, s390_r0);
+                       gboolean branchUn = is_unsigned (ins->next);
+                       if ((ins->inst_imm == 0) && (!branchUn)) {
+                               s390_ltr (code, ins->sreg1, ins->sreg1);
+                       } else {
+                               S390_SET (code, s390_r0, ins->inst_imm);
+                               if (branchUn)
+                                       s390_clr  (code, ins->sreg1, s390_r0);
+                               else
+                                       s390_cr   (code, ins->sreg1, s390_r0);
+                       }
                }
                        break;
                case OP_BREAK: {
                }
                        break;
                case OP_ADDCC: {
-                       CHECK_SRCDST_COM;
-                       s390_agr  (code, ins->dreg, src2);
+                       if (mono_hwcap_s390x_has_mlt) {
+                               s390_agrk (code, ins->dreg, ins->sreg1, ins->sreg2);
+                       } else {
+                               CHECK_SRCDST_COM;
+                               s390_agr  (code, ins->dreg, src2);
+                       }
                }
                        break;
                case OP_LADD: {
-                       CHECK_SRCDST_COM;
-                       s390_agr   (code, ins->dreg, src2);
+                       if (mono_hwcap_s390x_has_mlt) {
+                               s390_agrk (code, ins->dreg, ins->sreg1, ins->sreg2);
+                       } else {
+                               CHECK_SRCDST_COM;
+                               s390_agr   (code, ins->dreg, src2);
+                       }
                }
                        break;
                case OP_ADC: {
                }
                        break;
                case OP_ADD_IMM: {
-                       if (ins->dreg != ins->sreg1) {
-                               s390_lgr  (code, ins->dreg, ins->sreg1);
-                       }
-                       if (s390_is_imm16 (ins->inst_imm)) {
-                               s390_aghi (code, ins->dreg, ins->inst_imm);
-                       } else if (s390_is_imm32 (ins->inst_imm)) {
-                               s390_agfi (code, ins->dreg, ins->inst_imm);
+                       if (mono_hwcap_s390x_has_mlt) {
+                               if (s390_is_imm16 (ins->inst_imm)) {
+                                       s390_aghik(code, ins->dreg, ins->sreg1, ins->inst_imm);
+                               } else {
+                                       S390_SET  (code, s390_r0, ins->inst_imm);
+                                       s390_agrk (code, ins->dreg, ins->sreg1, s390_r0);
+                               }
                        } else {
-                               S390_SET  (code, s390_r0, ins->inst_imm);
-                               s390_agr  (code, ins->dreg, s390_r0);
+                               if (ins->dreg != ins->sreg1) {
+                                       s390_lgr  (code, ins->dreg, ins->sreg1);
+                               }
+                               if (s390_is_imm16 (ins->inst_imm)) {
+                                       s390_aghi (code, ins->dreg, ins->inst_imm);
+                               } else if (s390_is_imm32 (ins->inst_imm)) {
+                                       s390_agfi (code, ins->dreg, ins->inst_imm);
+                               } else {
+                                       S390_SET  (code, s390_r0, ins->inst_imm);
+                                       s390_agr  (code, ins->dreg, s390_r0);
+                               }
                        }
                }
                        break;
                        if (ins->dreg != ins->sreg1) {
                                s390_lgr  (code, ins->dreg, ins->sreg1);
                        }
-                       g_assert (s390_is_imm16 (ins->inst_imm));
-                       s390_aghi (code, ins->dreg, ins->inst_imm);
+                       if (s390_is_imm32 (ins->inst_imm)) {
+                               s390_agfi (code, ins->dreg, ins->inst_imm);
+                       } else {
+                               S390_SET  (code, s390_r0, ins->inst_imm);
+                               s390_agr  (code, ins->dreg, s390_r0);
+                       }
                }
                        break;
                case OP_ADC_IMM: {
                }
                        break;
                case OP_SUBCC: {
-                       CHECK_SRCDST_NCOM;
-                       s390_sgr (code, ins->dreg, src2);
+                       if (mono_hwcap_s390x_has_mlt) {
+                           s390_sgrk (code, ins->dreg, ins->sreg1, ins->sreg2);
+                       } else {
+                           CHECK_SRCDST_NCOM;
+                           s390_sgr (code, ins->dreg, src2);
+                       }
                }
                        break;
                case OP_LSUB: {
-                       CHECK_SRCDST_NCOM;
-                       s390_sgr  (code, ins->dreg, src2);
+                       if (mono_hwcap_s390x_has_mlt) {
+                           s390_sgrk (code, ins->dreg, ins->sreg1, ins->sreg2);
+                       } else {
+                           CHECK_SRCDST_NCOM;
+                           s390_sgr  (code, ins->dreg, src2);
+                       }
                }
                        break;
                case OP_SBB: {
                }
                        break;
                case OP_LAND: {
-                       if (ins->sreg1 == ins->dreg) {
-                               s390_ngr  (code, ins->dreg, ins->sreg2);
-                       } 
-                       else { 
-                               if (ins->sreg2 == ins->dreg) { 
-                                       s390_ngr (code, ins->dreg, ins->sreg1);
-                               }
-                               else { 
-                                       s390_lgr (code, ins->dreg, ins->sreg1);
-                                       s390_ngr (code, ins->dreg, ins->sreg2);
+                       if (mono_hwcap_s390x_has_mlt) {
+                               s390_ngrk (code, ins->dreg, ins->sreg1, ins->sreg2);
+                       } else {
+                               if (ins->sreg1 == ins->dreg) {
+                                       s390_ngr  (code, ins->dreg, ins->sreg2);
+                               } else { 
+                                       if (ins->sreg2 == ins->dreg) { 
+                                               s390_ngr (code, ins->dreg, ins->sreg1);
+                                       } else { 
+                                               s390_lgr (code, ins->dreg, ins->sreg1);
+                                               s390_ngr (code, ins->dreg, ins->sreg2);
+                                       }
                                }
                        }
                }
                        break;
                case OP_AND_IMM: {
-                       if (ins->dreg != ins->sreg1) {
-                               s390_lgr  (code, ins->dreg, ins->sreg1);
-                       }
                        S390_SET_MASK (code, s390_r0, ins->inst_imm);
-                       s390_ngr (code, ins->dreg, s390_r0);
+                       if (mono_hwcap_s390x_has_mlt) {
+                               s390_ngrk (code, ins->dreg, ins->sreg1, s390_r0);
+                       } else {
+                               if (ins->dreg != ins->sreg1) {
+                                       s390_lgr  (code, ins->dreg, ins->sreg1);
+                               }
+                               s390_ngr (code, ins->dreg, s390_r0);
+                       }
                }
                        break;
                case OP_LDIV: {
                }
                        break;
                case OP_LOR: {
-                       if (ins->sreg1 == ins->dreg) {
-                               s390_ogr  (code, ins->dreg, ins->sreg2);
-                       } 
-                       else { 
-                               if (ins->sreg2 == ins->dreg) { 
-                                       s390_ogr (code, ins->dreg, ins->sreg1);
-                               }
-                               else { 
-                                       s390_lgr (code, ins->dreg, ins->sreg1);
-                                       s390_ogr (code, ins->dreg, ins->sreg2);
+                       if (mono_hwcap_s390x_has_mlt) {
+                               s390_ogrk (code, ins->dreg, ins->sreg1, ins->sreg2);
+                       } else {
+                               if (ins->sreg1 == ins->dreg) {
+                                       s390_ogr  (code, ins->dreg, ins->sreg2);
+                               } else { 
+                                       if (ins->sreg2 == ins->dreg) { 
+                                               s390_ogr (code, ins->dreg, ins->sreg1);
+                                       } else { 
+                                               s390_lgr (code, ins->dreg, ins->sreg1);
+                                               s390_ogr (code, ins->dreg, ins->sreg2);
+                                       }
                                }
                        }
                }
                        break;
                case OP_OR_IMM: {
-                       if (ins->dreg != ins->sreg1) {
-                               s390_lgr  (code, ins->dreg, ins->sreg1);
-                       }
                        S390_SET_MASK(code, s390_r0, ins->inst_imm);
-                       s390_ogr (code, ins->dreg, s390_r0);
+                       if (mono_hwcap_s390x_has_mlt) {
+                               s390_ogrk (code, ins->dreg, ins->sreg1, s390_r0);
+                       } else {
+                               if (ins->dreg != ins->sreg1) {
+                                       s390_lgr  (code, ins->dreg, ins->sreg1);
+                               }
+                               s390_ogr (code, ins->dreg, s390_r0);
+                       }
                }
                        break;
                case OP_LXOR: {
-                       if (ins->sreg1 == ins->dreg) {
-                               s390_xgr  (code, ins->dreg, ins->sreg2);
-                       } 
-                       else { 
-                               if (ins->sreg2 == ins->dreg) { 
-                                       s390_xgr (code, ins->dreg, ins->sreg1);
-                               }
+                       if (mono_hwcap_s390x_has_mlt) {
+                               s390_xgrk (code, ins->dreg, ins->sreg1, ins->sreg2);
+                       } else {
+                               if (ins->sreg1 == ins->dreg) {
+                                       s390_xgr  (code, ins->dreg, ins->sreg2);
+                               } 
                                else { 
-                                       s390_lgr (code, ins->dreg, ins->sreg1);
-                                       s390_xgr (code, ins->dreg, ins->sreg2);
+                                       if (ins->sreg2 == ins->dreg) { 
+                                               s390_xgr (code, ins->dreg, ins->sreg1);
+                                       }
+                                       else { 
+                                               s390_lgr (code, ins->dreg, ins->sreg1);
+                                               s390_xgr (code, ins->dreg, ins->sreg2);
+                                       }
                                }
                        }
                }
                        break;
                case OP_XOR_IMM: {
-                       if (ins->dreg != ins->sreg1) {
-                               s390_lgr  (code, ins->dreg, ins->sreg1);
+                       S390_SET_MASK(code, s390_r0, ins->inst_imm);
+                       if (mono_hwcap_s390x_has_mlt) {
+                               s390_xgrk (code, ins->dreg, ins->sreg1, s390_r0);
+                       } else {
+                               if (ins->dreg != ins->sreg1) {
+                                       s390_lgr  (code, ins->dreg, ins->sreg1);
+                               }
+                               s390_xgr (code, ins->dreg, s390_r0);
                        }
-                       S390_SET_MASK (code, s390_r0, ins->inst_imm);
-                       s390_xgr (code, ins->dreg, s390_r0);
                }
                        break;
                case OP_LSHL: {
                }
                        break;
                case OP_IAND: {
-                       CHECK_SRCDST_NCOM_I;
-                       s390_ngr (code, ins->dreg, src2);
+                       if (mono_hwcap_s390x_has_mlt) {
+                               s390_ngrk (code, ins->dreg, ins->sreg1, ins->sreg2);
+                       } else {
+                               CHECK_SRCDST_NCOM_I;
+                               s390_ngr (code, ins->dreg, src2);
+                       }
                }
                        break;
                case OP_IAND_IMM: {
-                       if (ins->dreg != ins->sreg1) {
-                               s390_lgfr (code, ins->dreg, ins->sreg1);
-                       }
                        S390_SET_MASK (code, s390_r0, ins->inst_imm);
-                       s390_ngr  (code, ins->dreg, s390_r0);
+                       if (mono_hwcap_s390x_has_mlt) {
+                               s390_ngrk (code, ins->dreg, ins->sreg1, s390_r0);
+                       } else {
+                               if (ins->dreg != ins->sreg1) {
+                                       s390_lgfr (code, ins->dreg, ins->sreg1);
+                               }
+                               s390_ngr  (code, ins->dreg, s390_r0);
+                       }
                }
                        break;
                case OP_IDIV: {
                }
                        break;
                case OP_IOR: {
-                       CHECK_SRCDST_COM_I;
-                       s390_ogr (code, ins->dreg, src2);
+                       if (mono_hwcap_s390x_has_mlt) {
+                               s390_ogrk (code, ins->dreg, ins->sreg1, ins->sreg2);
+                       } else {
+                               CHECK_SRCDST_COM_I;
+                               s390_ogr (code, ins->dreg, src2);
+                       }
                }
                        break;
                case OP_IOR_IMM: {
-                       if (ins->dreg != ins->sreg1) {
-                               s390_lgfr (code, ins->dreg, ins->sreg1);
-                       }
                        S390_SET_MASK (code, s390_r0, ins->inst_imm);
-                       s390_ogr  (code, ins->dreg, s390_r0);
+                       if (mono_hwcap_s390x_has_mlt) {
+                               s390_ogrk (code, ins->dreg, ins->sreg1, s390_r0);
+                       } else {
+                               if (ins->dreg != ins->sreg1) {
+                                       s390_lgfr (code, ins->dreg, ins->sreg1);
+                               }
+                               s390_ogr  (code, ins->dreg, s390_r0);
+                       }
                }
                        break;
                case OP_IXOR: {
-                       CHECK_SRCDST_COM_I;
-                       s390_xgr (code, ins->dreg, src2);
+                       if (mono_hwcap_s390x_has_mlt) {
+                               s390_xgrk (code, ins->dreg, ins->sreg1, ins->sreg2);
+                       } else {
+                               CHECK_SRCDST_COM_I;
+                               s390_xgr (code, ins->dreg, src2);
+                       }
                }
                        break;
                case OP_IXOR_IMM: {
-                       if (ins->dreg != ins->sreg1) {
-                               s390_lgfr (code, ins->dreg, ins->sreg1);
-                       }
                        S390_SET_MASK (code, s390_r0, ins->inst_imm);
-                       s390_xgr  (code, ins->dreg, s390_r0);
+                       if (mono_hwcap_s390x_has_mlt) {
+                               s390_xgrk (code, ins->dreg, ins->sreg1, s390_r0);
+                       } else {
+                               if (ins->dreg != ins->sreg1) {
+                                       s390_lgfr (code, ins->dreg, ins->sreg1);
+                               }
+                               s390_xgr  (code, ins->dreg, s390_r0);
+                       }
                }
                        break;
                case OP_ISHL: {
                        s390_lghi(code, ins->dreg, 0);
                }
                        break;
+               case OP_ICNEQ: {
+                       s390_lghi(code, ins->dreg, 1);
+                       s390_jne (code, 4);
+                       s390_lghi(code, ins->dreg, 0);
+               }
+                       break;
+               case OP_ICGE: {
+                       s390_lghi(code, ins->dreg, 1);
+                       s390_jhe (code, 4);
+                       s390_lghi(code, ins->dreg, 0);
+               }
+                       break;
+               case OP_ICLE: {
+                       s390_lghi(code, ins->dreg, 1);
+                       s390_jle (code, 4);
+                       s390_lghi(code, ins->dreg, 0);
+               }
+                       break;
+               case OP_ICGE_UN: {
+                       s390_lghi(code, ins->dreg, 1);
+                       s390_jhe (code, 4);
+                       s390_lghi(code, ins->dreg, 0);
+               }
+                       break;
+               case OP_ICLE_UN: {
+                       s390_lghi(code, ins->dreg, 1);
+                       s390_jle (code, 4);
+                       s390_lghi(code, ins->dreg, 0);
+               }
+                       break;
                case OP_COND_EXC_EQ:
                case OP_COND_EXC_IEQ:
                        EMIT_COND_SYSTEM_EXCEPTION (S390_CC_EQ, ins->inst_p1);
                        EMIT_COND_BRANCH (ins, S390_CC_LE);
                        break;
  
+               case OP_S390_CRJ:
+                       EMIT_COMP_AND_BRANCH(ins, crj, cr);
+                       break;
+               case OP_S390_CLRJ:
+                       EMIT_COMP_AND_BRANCH(ins, clrj, clr);
+                       break;
+               case OP_S390_CGRJ:
+                       EMIT_COMP_AND_BRANCH(ins, cgrj, cgr);
+                       break;
+               case OP_S390_CLGRJ:
+                       EMIT_COMP_AND_BRANCH(ins, clgrj, clgr);
+                       break;
+               case OP_S390_CIJ:
+                       EMIT_COMP_AND_BRANCH_IMM(ins, crj, cr, ltr, FALSE);
+                       break;
+               case OP_S390_CLIJ:
+                       EMIT_COMP_AND_BRANCH_IMM(ins, clrj, clr, ltr, TRUE);
+                       break;
+               case OP_S390_CGIJ:
+                       EMIT_COMP_AND_BRANCH_IMM(ins, cgrj, cgr, ltgr, FALSE);
+                       break;
+               case OP_S390_CLGIJ:
+                       EMIT_COMP_AND_BRANCH_IMM(ins, clgrj, clgr, ltgr, TRUE);
+                       break;
                /* floating point opcodes */
                case OP_R8CONST: {
                        if (*((double *) ins->inst_p0) == 0) {
                        s390_lghi  (code, ins->dreg, 0);
                }
                        break;
+               case OP_FCNEQ: {
+                       s390_cdbr  (code, ins->sreg1, ins->sreg2);
+                       s390_lghi  (code, ins->dreg, 1);
+                       s390_jne   (code, 4);
+                       s390_lghi  (code, ins->dreg, 0);
+               }
+                       break;
+               case OP_FCGE: {
+                       s390_cdbr  (code, ins->sreg1, ins->sreg2);
+                       s390_lghi  (code, ins->dreg, 1);
+                       s390_jhe   (code, 4);
+                       s390_lghi  (code, ins->dreg, 0);
+               }
+                       break;
+               case OP_FCLE: {
+                       s390_cdbr  (code, ins->sreg1, ins->sreg2);
+                       s390_lghi  (code, ins->dreg, 1);
+                       s390_jle   (code, 4);
+                       s390_lghi  (code, ins->dreg, 0);
+               }
+                       break;
                case OP_FBEQ: {
                        short *o;
                        s390_jo (code, 0); CODEPTR(code, o);
                }
                        break;
                case OP_ATOMIC_ADD_I8: {
-                       s390_lgr (code, s390_r1, ins->sreg2);
-                       s390_lg  (code, s390_r0, 0, ins->inst_basereg, ins->inst_offset);
-                       s390_agr (code, s390_r1, s390_r0);
-                       s390_csg (code, s390_r0, s390_r1, ins->inst_basereg, ins->inst_offset);
-                       s390_jnz (code, -10);
-                       s390_lgr (code, ins->dreg, s390_r1);
+                       if (mono_hwcap_s390x_has_ia) {
+                               s390_laag (code, ins->dreg, ins->sreg2, ins->inst_basereg, ins->inst_offset);
+                               s390_agr  (code, ins->dreg, ins->sreg2);
+                       } else {
+                               s390_lgr (code, s390_r1, ins->sreg2);
+                               s390_lg  (code, s390_r0, 0, ins->inst_basereg, ins->inst_offset);
+                               s390_agr (code, s390_r1, s390_r0);
+                               s390_csg (code, s390_r0, s390_r1, ins->inst_basereg, ins->inst_offset);
+                               s390_jnz (code, -10);
+                               s390_lgr (code, ins->dreg, s390_r1);
+                       }
                }
                        break;  
                case OP_ATOMIC_EXCHANGE_I8: {
                }
                        break;  
                case OP_ATOMIC_ADD_I4: {
-                       s390_lgfr(code, s390_r1, ins->sreg2);
-                       s390_lgf (code, s390_r0, 0, ins->inst_basereg, ins->inst_offset);
-                       s390_agr (code, s390_r1, s390_r0);
-                       s390_cs  (code, s390_r0, s390_r1, ins->inst_basereg, ins->inst_offset);
-                       s390_jnz (code, -9);
-                       s390_lgfr(code, ins->dreg, s390_r1);
+                       if (mono_hwcap_s390x_has_ia) {
+                               s390_laa (code, ins->dreg, ins->sreg2, ins->inst_basereg, ins->inst_offset);
+                               s390_ar  (code, ins->dreg, ins->sreg2);
+                       } else {
+                               s390_lgfr(code, s390_r1, ins->sreg2);
+                               s390_lgf (code, s390_r0, 0, ins->inst_basereg, ins->inst_offset);
+                               s390_agr (code, s390_r1, s390_r0);
+                               s390_cs  (code, s390_r0, s390_r1, ins->inst_basereg, ins->inst_offset);
+                               s390_jnz (code, -9);
+                               s390_lgfr(code, ins->dreg, s390_r1);
+                       }
                }
                        break;  
                case OP_ATOMIC_EXCHANGE_I4: {
                        s390_mem (code);
                        break;
                case OP_GC_SAFE_POINT: {
-                       guint8 *br;
+                       short *br;
  
                        g_assert (mono_threads_is_coop_enabled ());
  
-                       s390_chi (code, ins->sreg1, 1); 
-                       s390_je  (code, 0); CODEPTR(code, br);
-                       mono_add_patch_info (cfg, code- cfg->native_code, MONO_PATCH_INFO_ABS,
+                       s390_ltg (code, s390_r0, 0, ins->sreg1, 0);     
+                       s390_jz  (code, 0); CODEPTR(code, br);
+                       mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_ABS,
                                             mono_threads_state_poll);
                        S390_CALL_TEMPLATE (code, s390_r14);
                        PTRSLOT (code, br);
@@@ -5413,7 -5768,7 +5769,7 @@@ mono_arch_patch_code (MonoCompile *cfg
                gconstpointer target = NULL;
  
                target = mono_resolve_patch_target (method, domain, code, 
-                                                                                       patch_info, run_cctors, error);
+                                                   patch_info, run_cctors, error);
                return_if_nok (error);
  
                switch (patch_info->type) {
@@@ -6132,7 -6487,7 +6488,7 @@@ mono_arch_emit_exceptions (MonoCompile 
  
  /*------------------------------------------------------------------*/
  /*                                                                  */
- /* Name               - mono_arch_finish_init                                 */
+ /* Name               - mono_arch_finish_init                             */
  /*                                                                  */
  /* Function   - Setup the JIT's Thread Level Specific Data.       */
  /*                                                                */
@@@ -6390,8 -6745,6 +6746,6 @@@ get_delegate_invoke_impl (MonoTrampInf
                mono_arch_flush_icache (start, size);
        }
  
-       MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_DELEGATE_INVOKE, NULL));
        if (has_target) {
                *info = mono_tramp_info_create ("delegate_invoke_impl_has_target", start, code - start, NULL, NULL);
        } else {
@@@ -6676,10 -7029,9 +7030,9 @@@ mono_arch_build_imt_trampoline (MonoVTa
        }
  
        mono_arch_flush_icache ((guint8*)start, (code - start));
-       MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_IMT_TRAMPOLINE, NULL));
  
        if (!fail_tramp) 
 -              mono_stats.imt_trampolines_size += (code - start);
 +              UnlockedAdd (&mono_stats.imt_trampolines_size, code - start);
  
        g_assert (code - start <= size);