**** Merged r40732-r40872 from MCS ****
[mono.git] / mono / mini / mini-s390.c
1 /*------------------------------------------------------------------*/
2 /*                                                                  */
3 /* Name        - mini-s390.c                                        */
4 /*                                                                  */
5 /* Function    - S/390 backend for the Mono code generator.         */
6 /*                                                                  */
7 /* Name        - Neale Ferguson (Neale.Ferguson@SoftwareAG-usa.com) */
8 /*                                                                  */
9 /* Date        - January, 2004                                      */
10 /*                                                                  */
11 /* Derivation  - From mini-x86 & mini-ppc by -                      */
12 /*               Paolo Molaro (lupus@ximian.com)                    */
13 /*               Dietmar Maurer (dietmar@ximian.com)                */
14 /*                                                                  */
15 /*------------------------------------------------------------------*/
16
17 /*------------------------------------------------------------------*/
18 /*                 D e f i n e s                                    */
19 /*------------------------------------------------------------------*/
20
21 #define NOT_IMPLEMENTED(x) \
22         g_error ("FIXME: %s is not yet implemented.", x);
23
24 #define EMIT_COND_BRANCH(ins,cond)                                                      \
25 {                                                                                       \
26 if (ins->flags & MONO_INST_BRLABEL) {                                                   \
27         if (ins->inst_i0->inst_c0) {                                                    \
28                 int displace;                                                           \
29                 displace = ((cfg->native_code + ins->inst_i0->inst_c0) - code) / 2;     \
30                 if (s390_is_uimm16(displace)) {                                         \
31                         s390_brc (code, cond, displace);                                \
32                 } else {                                                                \
33                         s390_jcl (code, cond, displace);                                \
34                 }                                                                       \
35         } else {                                                                        \
36                 mono_add_patch_info (cfg, code - cfg->native_code,                      \
37                                      MONO_PATCH_INFO_LABEL, ins->inst_i0);              \
38                 s390_jcl (code, cond, 0);                                               \
39         }                                                                               \
40 } else {                                                                                \
41         if (ins->inst_true_bb->native_offset) {                                         \
42                 int displace;                                                           \
43                 displace = ((cfg->native_code +                                         \
44                             ins->inst_true_bb->native_offset) - code) / 2;              \
45                 if (s390_is_uimm16(displace)) {                                         \
46                         s390_brc (code, cond, displace);                                \
47                 } else {                                                                \
48                         s390_jcl (code, cond, displace);                                \
49                 }                                                                       \
50         } else {                                                                        \
51                 mono_add_patch_info (cfg, code - cfg->native_code,                      \
52                                      MONO_PATCH_INFO_BB, ins->inst_true_bb);            \
53                 s390_jcl (code, cond, 0);                                               \
54         }                                                                               \
55 }                                                                                       \
56 }
57
58 #define EMIT_UNCOND_BRANCH(ins)                                                         \
59 {                                                                                       \
60 if (ins->flags & MONO_INST_BRLABEL) {                                                   \
61         if (ins->inst_i0->inst_c0) {                                                    \
62                 int displace;                                                           \
63                 displace = ((cfg->native_code + ins->inst_i0->inst_c0) - code) / 2;     \
64                 if (s390_is_uimm16(displace)) {                                         \
65                         s390_brc (code, S390_CC_UN, displace);                          \
66                 } else {                                                                \
67                         s390_jcl (code, S390_CC_UN, displace);                          \
68                 }                                                                       \
69         } else {                                                                        \
70                 mono_add_patch_info (cfg, code - cfg->native_code,                      \
71                                      MONO_PATCH_INFO_LABEL, ins->inst_i0);              \
72                 s390_jcl (code, S390_CC_UN, 0);                                         \
73         }                                                                               \
74 } else {                                                                                \
75         if (ins->inst_target_bb->native_offset) {                                       \
76                 int displace;                                                           \
77                 displace = ((cfg->native_code +                                         \
78                             ins->inst_target_bb->native_offset) - code) / 2;            \
79                 if (s390_is_uimm16(displace)) {                                         \
80                         s390_brc (code, S390_CC_UN, displace);                          \
81                 } else {                                                                \
82                         s390_jcl (code, S390_CC_UN, displace);                          \
83                 }                                                                       \
84         } else {                                                                        \
85                 mono_add_patch_info (cfg, code - cfg->native_code,                      \
86                                      MONO_PATCH_INFO_BB, ins->inst_target_bb);          \
87                 s390_jcl (code, S390_CC_UN, 0);                                         \
88         }                                                                               \
89 }                                                                                       \
90 }
91
92 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name)                       \
93         do {                                                            \
94                 mono_add_patch_info (cfg, code - cfg->native_code,      \
95                                     MONO_PATCH_INFO_EXC, exc_name);     \
96                 s390_jcl (code, cond, 0);                               \
97         } while (0); 
98
99 #define CHECK_SRCDST_COM                                                \
100         if (ins->dreg == ins->sreg2) {                                  \
101                 src2 = ins->sreg1;                                      \
102         } else {                                                        \
103                 src2 = ins->sreg2;                                      \
104                 if (ins->dreg != ins->sreg1) {                          \
105                         s390_lr  (code, ins->dreg, ins->sreg1);         \
106                 }                                                       \
107         }
108
109 #define CHECK_SRCDST_NCOM                                               \
110         if (ins->dreg == ins->sreg2) {                                  \
111                 src2 = s390_r13;                                        \
112                 s390_lr  (code, s390_r13, ins->sreg2);                  \
113         } else {                                                        \
114                 src2 = ins->sreg2;                                      \
115         }                                                               \
116         if (ins->dreg != ins->sreg1) {                                  \
117                 s390_lr  (code, ins->dreg, ins->sreg1);                 \
118         }
119
120 #define CHECK_SRCDST_NCOM_F                                             \
121         if (ins->dreg == ins->sreg2) {                                  \
122                 src2 = s390_f15;                                        \
123                 s390_ldr (code, s390_r13, ins->sreg2);                  \
124         } else {                                                        \
125                 src2 = ins->sreg2;                                      \
126         }                                                               \
127         if (ins->dreg != ins->sreg1) {                                  \
128                 s390_ldr (code, ins->dreg, ins->sreg1);                 \
129         }
130
131 #undef DEBUG
132 #define DEBUG(a) if (cfg->verbose_level > 1) a
133
134 #define MAX_EXC 16
135
136 /*----------------------------------------*/
137 /* use s390_r2-s390_r5 as temp registers  */
138 /*----------------------------------------*/
139 #define S390_CALLER_REGS  (0x10fc)
140 #define reg_is_freeable(r) (S390_CALLER_REGS & 1 << (r))
141
142 /*----------------------------------------*/
143 /* use s390_f1/s390_f3-s390_f15 as temps  */
144 /*----------------------------------------*/
145 #define S390_CALLER_FREGS (0xfffa)
146 #define freg_is_freeable(r) ((r) >= 1 && (r) <= 14)
147
148 #define S390_TRACE_STACK_SIZE (5*sizeof(gint32)+3*sizeof(gdouble))
149
150 #define MAX (a, b) ((a) > (b) ? (a) : (b))
151
152 /*========================= End of Defines =========================*/
153
154 /*------------------------------------------------------------------*/
155 /*                 I n c l u d e s                                  */
156 /*------------------------------------------------------------------*/
157
158 #include "mini.h"
159 #include <string.h>
160
161 #include <mono/metadata/appdomain.h>
162 #include <mono/metadata/debug-helpers.h>
163 #include <mono/metadata/profiler-private.h>
164 #include <mono/utils/mono-math.h>
165
166 #include "mini-s390.h"
167 #include "inssel.h"
168 #include "cpu-s390.h"
169
170 /*========================= End of Includes ========================*/
171
172 /*------------------------------------------------------------------*/
173 /*                 T y p e d e f s                                  */
174 /*------------------------------------------------------------------*/
175
176 typedef struct {
177         guint stack_size,
178               local_size,
179               code_size,
180               retStruct;
181 } size_data;    
182
183 /*------------------------------------------------------------------*/
184 /* Used by the instrument_emit_epilog                               */
185 /*------------------------------------------------------------------*/
186
187 enum {
188         SAVE_NONE,
189         SAVE_STRUCT,
190         SAVE_ONE,
191         SAVE_TWO,
192         SAVE_FP
193 };
194
195 typedef struct {
196         int born_in;
197         int killed_in;
198         int last_use;
199         int prev_use;
200 } RegTrack;
201
202 typedef struct InstList InstList;
203
204 struct InstList {
205         InstList *prev;
206         InstList *next;
207         MonoInst *data;
208 };
209
210 enum {
211         RegTypeGeneral,
212         RegTypeBase,
213         RegTypeFP,
214         RegTypeStructByVal,
215         RegTypeStructByAddr
216 };
217
218 typedef struct {
219         gint32  offset;         /* offset from caller's stack */
220         gint32  offparm;        /* offset on callee's stack */
221         guint16 vtsize;         /* in param area */
222         guint8  reg;
223         guint8  regtype;        /* See RegType* */
224         guint32 size;           /* Size of structure used by RegTypeStructByVal */
225 } ArgInfo;
226
227 typedef struct {
228         int nargs;
229         guint32 stack_usage;
230         guint32 struct_ret;
231         ArgInfo ret;
232         ArgInfo sigCookie;
233         ArgInfo args [1];
234 } CallInfo;
235
236 typedef struct {
237         gint32  gr[5];          /* R2-R6                            */
238         gdouble fp[3];          /* F0-F2                            */
239 } __attribute__ ((packed)) RegParm;
240
241 /*========================= End of Typedefs ========================*/
242
243 /*------------------------------------------------------------------*/
244 /*                   P r o t o t y p e s                            */
245 /*------------------------------------------------------------------*/
246
247 static guint32 * emit_memcpy (guint8 *, int, int, int, int, int);
248 static void indent (int);
249 static guint8 * backUpStackPtr(MonoCompile *, guint8 *);
250 static void decodeParm (MonoType *, void *, int);
251 static void enter_method (MonoMethod *, RegParm *, char *);
252 static void leave_method (MonoMethod *, ...);
253 static gboolean is_regsize_var (MonoType *);
254 static inline void add_general (guint *, size_data *, ArgInfo *, gboolean);
255 static inline void add_float (guint *, size_data *, ArgInfo *);
256 static CallInfo * calculate_sizes (MonoMethodSignature *, size_data *, gboolean);
257 static void peephole_pass (MonoCompile *, MonoBasicBlock *);
258 static int mono_spillvar_offset (MonoCompile *, int);
259 static int mono_spillvar_offset_float (MonoCompile *, int);
260 static void print_ins (int, MonoInst *);
261 static void print_regtrack (RegTrack *, int);
262 static InstList * inst_list_prepend (MonoMemPool *, InstList *, MonoInst *);
263 static int get_register_force_spilling (MonoCompile *, InstList *, MonoInst *, int);
264 static int get_register_spilling (MonoCompile *, InstList *, MonoInst *, guint32, int);
265 static int get_float_register_spilling (MonoCompile *, InstList *, MonoInst *, guint32, int);
266 static MonoInst * create_copy_ins (MonoCompile *, int, int, MonoInst *);
267 static MonoInst * create_copy_ins_float (MonoCompile *, int, int, MonoInst *);
268 static MonoInst * create_spilled_store (MonoCompile *, int, int, int, MonoInst *);
269 static MonoInst * create_spilled_store_float (MonoCompile *, int, int, int, MonoInst *);
270 static void insert_before_ins (MonoInst *, InstList *, MonoInst *);
271 static int alloc_int_reg (MonoCompile *, InstList *, MonoInst *, int, guint32);
272 static guchar * emit_float_to_int (MonoCompile *, guchar *, int, int, int, gboolean);
273 static unsigned char * mono_emit_stack_alloc (guchar *, MonoInst *);
274
275 /*========================= End of Prototypes ======================*/
276
277 /*------------------------------------------------------------------*/
278 /*                 G l o b a l   V a r i a b l e s                  */
279 /*------------------------------------------------------------------*/
280
281 int mono_exc_esp_offset = 0;
282
283 static int indent_level = 0;
284
285 static const char*const * ins_spec = s390;
286
287 static gboolean tls_offset_inited = FALSE;
288
289 static int appdomain_tls_offset = -1,
290            lmf_tls_offset = -1,
291            thread_tls_offset = -1;
292
293 #if 0
294
295 extern __thread MonoDomain *tls_appdomain;
296 extern __thread MonoThread *tls_current_object;
297 extern __thread gpointer   mono_lmf_addr;
298                 
299 #endif
300
301 /*====================== End of Global Variables ===================*/
302
303 /*------------------------------------------------------------------*/
304 /*                                                                  */
305 /* Name         - mono_arch_regname                                 */
306 /*                                                                  */
307 /* Function     - Returns the name of the register specified by     */
308 /*                the input parameter.                              */
309 /*                                                                  */
310 /*------------------------------------------------------------------*/
311
312 const char*
313 mono_arch_regname (int reg) {
314         static const char * rnames[] = {
315                 "s390_r0", "s390_sp", "s390_r2", "s390_r3", "s390_r4",
316                 "s390_r5", "s390_r6", "s390_r7", "s390_r8", "s390_r9",
317                 "s390_r10", "s390_r11", "s390_r12", "s390_r13", "s390_r14",
318                 "s390_r15"
319         };
320         if (reg >= 0 && reg < 16)
321                 return rnames [reg];
322         return "unknown";
323 }
324
325 /*========================= End of Function ========================*/
326
327 /*------------------------------------------------------------------*/
328 /*                                                                  */
329 /* Name         - emit_memcpy                                       */
330 /*                                                                  */
331 /* Function     - Emit code to move from memory-to-memory based on  */
332 /*                the size of the variable. r0 is overwritten.      */
333 /*                                                                  */
334 /*------------------------------------------------------------------*/
335
336 static guint32*
337 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
338 {
339         switch (size) {
340                 case 4 :
341                         s390_l  (code, s390_r0, 0, sreg, soffset);
342                         s390_st (code, s390_r0, 0, dreg, doffset);
343                         break;
344
345                 case 3 : 
346                         s390_icm  (code, s390_r0, 14, sreg, soffset);
347                         s390_stcm (code, s390_r0, 14, dreg, doffset);
348                         break;
349
350                 case 2 : 
351                         s390_lh  (code, s390_r0, 0, sreg, soffset);
352                         s390_sth (code, s390_r0, 0, dreg, doffset);
353                         break;
354
355                 case 1 : 
356                         s390_ic  (code, s390_r0, 0, sreg, soffset);
357                         s390_stc (code, s390_r0, 0, dreg, doffset);
358                         break;
359         
360                 default : 
361                         while (size > 0) {
362                                 int len;
363
364                                 if (size > 256) 
365                                         len = 256;
366                                 else
367                                         len = size;
368                                 s390_mvc (code, len, dreg, doffset, sreg, soffset);
369                                 size -= len;
370                         }
371         }
372         return code;
373 }
374
375 /*========================= End of Function ========================*/
376
377 /*------------------------------------------------------------------*/
378 /*                                                                  */
379 /* Name         - arch_get_argument_info                            */
380 /*                                                                  */
381 /* Function     - Gathers information on parameters such as size,   */
382 /*                alignment, and padding. arg_info should be large  */
383 /*                enough to hold param_count + 1 entries.           */
384 /*                                                                  */
385 /* Parameters   - @csig - Method signature                          */
386 /*                @param_count - No. of parameters to consider      */
387 /*                @arg_info - An array to store the result info     */
388 /*                                                                  */
389 /* Returns      - Size of the activation frame                      */
390 /*                                                                  */
391 /*------------------------------------------------------------------*/
392
393 int
394 mono_arch_get_argument_info (MonoMethodSignature *csig, 
395                              int param_count, 
396                              MonoJitArgumentInfo *arg_info)
397 {
398         int k, frame_size = 0;
399         int size, align, pad;
400         int offset = 8;
401
402         if (MONO_TYPE_ISSTRUCT (csig->ret)) { 
403                 frame_size += sizeof (gpointer);
404                 offset += 4;
405         }
406
407         arg_info [0].offset = offset;
408
409         if (csig->hasthis) {
410                 frame_size += sizeof (gpointer);
411                 offset += 4;
412         }
413
414         arg_info [0].size = frame_size;
415
416         for (k = 0; k < param_count; k++) {
417                 
418                 if (csig->pinvoke)
419                         size = mono_type_native_stack_size (csig->params [k], &align);
420                 else
421                         size = mono_type_stack_size (csig->params [k], &align);
422
423                 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1); 
424                 arg_info [k].pad = pad;
425                 frame_size += size;
426                 arg_info [k + 1].pad = 0;
427                 arg_info [k + 1].size = size;
428                 offset += pad;
429                 arg_info [k + 1].offset = offset;
430                 offset += size;
431         }
432
433         align = MONO_ARCH_FRAME_ALIGNMENT;
434         frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
435         arg_info [k].pad = pad;
436
437         return frame_size;
438 }
439
440 /*========================= End of Function ========================*/
441
442 /*------------------------------------------------------------------*/
443 /*                                                                  */
444 /* Name         - retFitsInReg.                                     */
445 /*                                                                  */
446 /* Function     - Determines if a value can be returned in one or   */
447 /*                two registers.                                    */
448 /*                                                                  */
449 /*------------------------------------------------------------------*/
450
451 static inline gboolean
452 retFitsInReg(guint32 size)
453 {
454         switch (size) {
455                 case 0:
456                 case 1:
457                 case 2:
458                 case 4:
459                 case 8:
460                         return (TRUE);
461                 break;
462                 default:
463                         return (FALSE);
464         }
465 }
466
467 /*========================= End of Function ========================*/
468
469 /*------------------------------------------------------------------*/
470 /*                                                                  */
471 /* Name         - backStackPtr.                                     */
472 /*                                                                  */
473 /* Function     - Restore Stack Pointer to previous frame.          */
474 /*                                                                  */
475 /*------------------------------------------------------------------*/
476
477 static inline guint8 *
478 backUpStackPtr(MonoCompile *cfg, guint8 *code)
479 {
480         int stackSize = cfg->stack_usage;
481
482         if (s390_is_uimm16 (cfg->stack_usage)) {
483                 s390_ahi  (code, STK_BASE, cfg->stack_usage);
484         } else { 
485                 while (stackSize > 32767) {
486                         s390_ahi  (code, STK_BASE, 32767);
487                         stackSize -= 32767;
488                 }
489                 s390_ahi  (code, STK_BASE, stackSize);
490         }
491         return (code);
492 }
493
494 /*========================= End of Function ========================*/
495
496 /*------------------------------------------------------------------*/
497 /*                                                                  */
498 /* Name         - indent                                            */
499 /*                                                                  */
500 /* Function     - Perform nice indenting to current level           */
501 /*                                                                  */
502 /*------------------------------------------------------------------*/
503
504 static void 
505 indent (int diff) {
506         int v;
507         if (diff < 0)
508                 indent_level += diff;
509         v = indent_level;
510         printf("[%3d] ",v);
511         while (v-- > 0) {
512                 printf (". ");
513         }
514         if (diff > 0) 
515                 indent_level += diff;
516 }
517
518 /*========================= End of Function ========================*/
519
520 /*------------------------------------------------------------------*/
521 /*                                                                  */
522 /* Name         - decodeParm                                        */
523 /*                                                                  */
524 /* Function     - Decode a parameter for the trace.                 */
525 /*                                                                  */
526 /*------------------------------------------------------------------*/
527
528 static void 
529 decodeParm(MonoType *type, void *curParm, int size)
530 {
531         guint32 simpleType;
532
533         if (type->byref) {
534                 printf("[BYREF:%p], ", *((char **) curParm));
535         } else {
536                 simpleType = mono_type_get_underlying_type(type)->type;
537 enum_parmtype:
538                 switch (simpleType) {
539                         case MONO_TYPE_I :
540                                 printf ("[INTPTR:%p], ", *((int **) curParm));
541                                 break;
542                         case MONO_TYPE_U :
543                                 printf ("[UINTPTR:%p], ", *((int **) curParm));
544                                 break;
545                         case MONO_TYPE_BOOLEAN :
546                                 printf ("[BOOL:%p], ", *((int *) curParm));
547                                 break;
548                         case MONO_TYPE_CHAR :
549                                 printf ("[CHAR:%p], ", *((int *) curParm));
550                                 break;
551                         case MONO_TYPE_I1 :
552                                 printf ("[INT1:%d], ", *((int *) curParm));
553                                 break; 
554                         case MONO_TYPE_I2 :
555                                 printf ("[INT2:%d], ", *((int *) curParm));
556                                 break; 
557                         case MONO_TYPE_I4 :
558                                 printf ("[INT4:%d], ", *((int *) curParm));
559                                 break; 
560                         case MONO_TYPE_U1 :
561                                 printf ("[UINT1:%u], ", *((unsigned int *) curParm));
562                                 break; 
563                         case MONO_TYPE_U2 :
564                                 printf ("[UINT2:%u], ", *((guint16 *) curParm));
565                                 break; 
566                         case MONO_TYPE_U4 :
567                                 printf ("[UINT4:%u], ", *((guint32 *) curParm));
568                                 break; 
569                         case MONO_TYPE_U8 :
570                                 printf ("[UINT8:%llu], ", *((guint64 *) curParm));
571                                 break; 
572                         case MONO_TYPE_STRING : {
573                                 MonoString *s = *((MonoString **) curParm);
574                                 if (s) {
575                                         g_assert (((MonoObject *) s)->vtable->klass == mono_defaults.string_class);
576                                         printf("[STRING:%p:%s], ", s, mono_string_to_utf8(s));
577                                 } else {
578                                         printf("[STRING:null], ");
579                                 }
580                                 break;
581                         }
582                         case MONO_TYPE_CLASS :
583                         case MONO_TYPE_OBJECT : {
584                                 MonoObject *obj = *((MonoObject **) curParm);
585                                 MonoClass *class;
586                                 if ((obj) && (obj->vtable)) {
587                                         printf("[CLASS/OBJ:");
588                                         class = obj->vtable->klass;
589                                         if (class == mono_defaults.string_class) {
590                                                 printf("[STRING:%p:%s]", 
591                                                        *obj, mono_string_to_utf8 (obj));
592                                         } else if (class == mono_defaults.int32_class) { 
593                                                 printf("[INT32:%p:%d]", 
594                                                         obj, *(gint32 *)((char *)obj + sizeof (MonoObject)));
595                                         } else
596                                                 printf("[%s.%s:%p]", 
597                                                        class->name_space, class->name, obj);
598                                         printf("], ");
599                                 } else {
600                                         printf("[OBJECT:null], ");
601                                 }
602                                 break;
603                         }
604                         case MONO_TYPE_PTR :
605                                 printf("[PTR:%p], ", *((gpointer **) (curParm)));
606                                 break;
607                         case MONO_TYPE_FNPTR :
608                                 printf("[FNPTR:%p], ", *((gpointer **) (curParm)));
609                                 break;
610                         case MONO_TYPE_ARRAY :
611                                 printf("[ARRAY:%p], ", *((gpointer **) (curParm)));
612                                 break;
613                         case MONO_TYPE_SZARRAY :
614                                 printf("[SZARRAY:%p], ", *((gpointer **) (curParm)));
615                                 break;
616                         case MONO_TYPE_I8 :
617                                 printf("[INT8:%lld], ", *((gint64 *) (curParm)));
618                                 break;
619                         case MONO_TYPE_R4 :
620                                 printf("[FLOAT4:%f], ", *((float *) (curParm)));
621                                 break;
622                         case MONO_TYPE_R8 :
623                                 printf("[FLOAT8:%g], ", *((double *) (curParm)));
624                                 break;
625                         case MONO_TYPE_VALUETYPE : {
626                                 int i;
627                                 MonoMarshalType *info;
628
629                                 if (type->data.klass->enumtype) {
630                                         simpleType = type->data.klass->enum_basetype->type;
631                                         printf("{VALUETYPE} - ");
632                                         goto enum_parmtype;
633                                 }
634
635                                 info = mono_marshal_load_type_info (type->data.klass);
636
637                                 if ((info->native_size == sizeof(float)) &&
638                                     (info->num_fields  == 1) &&
639                                     (info->fields[0].field->type->type == MONO_TYPE_R4)) {
640                                         printf("[FLOAT4:%f], ", *((float *) (curParm)));
641                                         break;
642                                 }
643
644                                 if ((info->native_size == sizeof(double)) &&
645                                     (info->num_fields  == 1) &&
646                                     (info->fields[0].field->type->type == MONO_TYPE_R8)) {
647                                         printf("[FLOAT8:%g], ", *((double *) (curParm)));
648                                         break;
649                                 }
650
651                                 printf("[VALUETYPE:");
652                                 for (i = 0; i < size; i++)
653                                         printf("%02x,", *((guint8 *)curParm+i));
654                                 printf("]");
655                                 break;
656                         }
657                         case MONO_TYPE_TYPEDBYREF: {
658                                 int i;
659                                 printf("[TYPEDBYREF:");
660                                 for (i = 0; i < size; i++)
661                                         printf("%02x,", *((guint8 *)curParm+i));
662                                 printf("]");
663                                 break;
664                         }
665                         default :
666                                 printf("[?? - %d], ",simpleType);
667                 }
668         }
669 }
670
671 /*========================= End of Function ========================*/
672
673 /*------------------------------------------------------------------*/
674 /*                                                                  */
675 /* Name         - enter_method                                      */
676 /*                                                                  */
677 /* Function     - Perform tracing of the entry to the current       */
678 /*                method.                                           */
679 /*                                                                  */
680 /*------------------------------------------------------------------*/
681
682 static void
683 enter_method (MonoMethod *method, RegParm *rParm, char *sp)
684 {
685         int i, oParm = 0, iParm = 0;
686         MonoClass *class;
687         MonoObject *obj;
688         MonoJitArgumentInfo *arg_info;
689         MonoMethodSignature *sig;
690         char *fname;
691         guint32 ip;
692         CallInfo *cinfo;
693         ArgInfo *ainfo;
694         size_data sz;
695         void *curParm;
696
697         fname = mono_method_full_name (method, TRUE);
698         indent (1);
699         printf ("ENTER: %s(", fname);
700         g_free (fname);
701
702         ip  = (*(guint32 *) (sp+S390_RET_ADDR_OFFSET)) & 0x7fffffff;
703         printf (") ip: %p sp: %p - ", ip, sp); 
704
705         if (rParm == NULL)
706                 return;
707         
708         sig = mono_method_signature (method);
709         
710         cinfo = calculate_sizes (sig, &sz, sig->pinvoke);
711
712         if (cinfo->struct_ret) {
713                 printf ("[VALUERET:%p], ", rParm->gr[0]);
714                 iParm = 1;
715         }
716
717         if (sig->hasthis) {
718                 gpointer *this = (gpointer *) rParm->gr[iParm];
719                 obj = (MonoObject *) this;
720                 if (method->klass->valuetype) { 
721                         if (obj) {
722                                 printf("this:[value:%p:%08x], ", 
723                                        this, *((guint32 *)(this+sizeof(MonoObject))));
724                         } else 
725                                 printf ("this:[NULL], ");
726                 } else {
727                         if (obj) {
728                                 class = obj->vtable->klass;
729                                 if (class == mono_defaults.string_class) {
730                                         printf ("this:[STRING:%p:%s], ", 
731                                                 obj, mono_string_to_utf8 ((MonoString *)obj));
732                                 } else {
733                                         printf ("this:%p[%s.%s], ", 
734                                                 obj, class->name_space, class->name);
735                                 }
736                         } else 
737                                 printf ("this:NULL, ");
738                 }
739                 oParm++;
740         }
741                                         
742         for (i = 0; i < sig->param_count; ++i) {
743                 ainfo = cinfo->args + (i + oParm);
744                 switch (ainfo->regtype) {
745                         case RegTypeGeneral :
746                                 decodeParm(sig->params[i], &(rParm->gr[ainfo->reg-2]), ainfo->size);
747                                 break;
748                         case RegTypeFP :
749                                 decodeParm(sig->params[i], &(rParm->fp[ainfo->reg]), ainfo->size);
750                                 break;
751                         case RegTypeBase :
752                                 decodeParm(sig->params[i], sp+ainfo->offset, ainfo->size);
753                                 break;
754                         case RegTypeStructByVal :
755                                 if (ainfo->reg != STK_BASE) 
756                                         curParm = &(rParm->gr[ainfo->reg-2]);
757                                 else
758                                         curParm = sp+ainfo->offset;
759
760                                 if (retFitsInReg (ainfo->vtsize)) 
761                                         decodeParm(sig->params[i], 
762                                                    curParm,
763                                                    ainfo->size);
764                                 else
765                                         decodeParm(sig->params[i], 
766                                                    *((char **) curParm),
767                                                    ainfo->vtsize);
768                                 break;
769                         case RegTypeStructByAddr :
770                                 if (ainfo->reg != STK_BASE) 
771                                         curParm = &(rParm->gr[ainfo->reg-2]);
772                                 else
773                                         curParm = sp+ainfo->offset;
774
775                                 decodeParm(sig->params[i], 
776                                            *((char **) curParm),
777                                            ainfo->vtsize);
778                                 break;
779                                 
780                         default :
781                                 printf("???, ");
782                 }
783         }       
784         printf("\n");
785         g_free(cinfo);
786 }
787
788 /*========================= End of Function ========================*/
789
790 /*------------------------------------------------------------------*/
791 /*                                                                  */
792 /* Name         - leave_method                                      */
793 /*                                                                  */
794 /* Function     -                                                   */
795 /*                                                                  */
796 /*------------------------------------------------------------------*/
797
798 static void
799 leave_method (MonoMethod *method, ...)
800 {
801         MonoType *type;
802         char *fname;
803         guint32 ip;
804         va_list ap;
805
806         va_start(ap, method);
807
808         fname = mono_method_full_name (method, TRUE);
809         indent (-1);
810         printf ("LEAVE: %s", fname);
811         g_free (fname);
812
813         type = mono_method_signature (method)->ret;
814
815 handle_enum:
816         switch (type->type) {
817         case MONO_TYPE_VOID:
818                 break;
819         case MONO_TYPE_BOOLEAN: {
820                 int val = va_arg (ap, int);
821                 if (val)
822                         printf ("[TRUE:%d]", val);
823                 else 
824                         printf ("[FALSE]");
825                         
826                 break;
827         }
828         case MONO_TYPE_CHAR: {
829                 int val = va_arg (ap, int);
830                 printf ("[CHAR:%d]", val);
831                 break;
832         }
833         case MONO_TYPE_I1: {
834                 int val = va_arg (ap, int);
835                 printf ("[INT1:%d]", val);
836                 break;
837         }
838         case MONO_TYPE_U1: {
839                 int val = va_arg (ap, int);
840                 printf ("[UINT1:%d]", val);
841                 break;
842         }
843         case MONO_TYPE_I2: {
844                 int val = va_arg (ap, int);
845                 printf ("[INT2:%d]", val);
846                 break;
847         }
848         case MONO_TYPE_U2: {
849                 int val = va_arg (ap, int);
850                 printf ("[UINT2:%d]", val);
851                 break;
852         }
853         case MONO_TYPE_I4: {
854                 int val = va_arg (ap, int);
855                 printf ("[INT4:%d]", val);
856                 break;
857         }
858         case MONO_TYPE_U4: {
859                 int val = va_arg (ap, int);
860                 printf ("[UINT4:%d]", val);
861                 break;
862         }
863         case MONO_TYPE_I: {
864                 int *val = va_arg (ap, int*);
865                 printf ("[INT:%d]", val);
866                 printf("]");
867                 break;
868         }
869         case MONO_TYPE_U: {
870                 int *val = va_arg (ap, int*);
871                 printf ("[UINT:%d]", val);
872                 printf("]");
873                 break;
874         }
875         case MONO_TYPE_STRING: {
876                 MonoString *s = va_arg (ap, MonoString *);
877 ;
878                 if (s) {
879                         g_assert (((MonoObject *)s)->vtable->klass == mono_defaults.string_class);
880                         printf ("[STRING:%p:%s]", s, mono_string_to_utf8 (s));
881                 } else 
882                         printf ("[STRING:null], ");
883                 break;
884         }
885         case MONO_TYPE_CLASS: 
886         case MONO_TYPE_OBJECT: {
887                 MonoObject *o = va_arg (ap, MonoObject *);
888
889                 if ((o) && (o->vtable)) {
890                         if (o->vtable->klass == mono_defaults.boolean_class) {
891                                 printf ("[BOOLEAN:%p:%d]", o, *((guint8 *)o + sizeof (MonoObject)));            
892                         } else if  (o->vtable->klass == mono_defaults.int32_class) {
893                                 printf ("[INT32:%p:%d]", o, *((gint32 *)((char *)o + sizeof (MonoObject))));    
894                         } else if  (o->vtable->klass == mono_defaults.int64_class) {
895                                 printf ("[INT64:%p:%lld]", o, *((gint64 *)((char *)o + sizeof (MonoObject))));  
896                         } else
897                                 printf ("[%s.%s:%p]", o->vtable->klass->name_space, o->vtable->klass->name, o);
898                 } else
899                         printf ("[OBJECT:%p]", o);
900                
901                 break;
902         }
903         case MONO_TYPE_PTR:
904         case MONO_TYPE_FNPTR:
905         case MONO_TYPE_ARRAY:
906         case MONO_TYPE_SZARRAY: {
907                 gpointer p = va_arg (ap, gpointer);
908                 printf ("[result=%p]", p);
909                 break;
910         }
911         case MONO_TYPE_I8: {
912                 gint64 l =  va_arg (ap, gint64);
913                 printf ("[LONG:%lld]", l);
914                 break;
915         }
916         case MONO_TYPE_U8: {
917                 guint64 l =  va_arg (ap, guint64);
918                 printf ("[ULONG:%llu]", l);
919                 break;
920         }
921         case MONO_TYPE_R4: {
922                 double f = va_arg (ap, double);
923                 printf ("[FLOAT4:%f]\n", (float) f);
924                 break;
925         }
926         case MONO_TYPE_R8: {
927                 double f = va_arg (ap, double);
928                 printf ("[FLOAT8:%g]\n", f);
929                 break;
930         }
931         case MONO_TYPE_VALUETYPE: {
932                 MonoMarshalType *info;
933                 if (type->data.klass->enumtype) {
934                         type = type->data.klass->enum_basetype;
935                         goto handle_enum;
936                 } else {
937                         guint8 *p = va_arg (ap, gpointer);
938                         int j, size, align;
939
940                         info = mono_marshal_load_type_info (type->data.klass);
941
942                         if ((info->native_size == sizeof(float)) &&
943                             (info->num_fields  == 1) &&
944                             (info->fields[0].field->type->type == MONO_TYPE_R4)) {
945                                 double f = va_arg (ap, double);
946                                 printf("[FLOAT4:%f]\n", (float) f);
947                                 break;
948                         }
949
950                         if ((info->native_size == sizeof(double)) &&
951                             (info->num_fields  == 1) &&
952                             (info->fields[0].field->type->type == MONO_TYPE_R8)) {
953                                 double f = va_arg (ap, double);
954                                 printf("[FLOAT8:%g]\n", f);
955                                 break;
956                         }
957
958                         size = mono_type_size (type, &align);
959                         printf ("[");
960                         for (j = 0; p && j < size; j++)
961                                 printf ("%02x,", p [j]);
962                         printf ("]");
963                 }
964                 break;
965         }
966         case MONO_TYPE_TYPEDBYREF: {
967                 guint8 *p = va_arg (ap, gpointer);
968                 int j, size, align;
969                 size = mono_type_size (type, &align);
970                 printf ("[");
971                 for (j = 0; p && j < size; j++)
972                         printf ("%02x,", p [j]);
973                 printf ("]");
974         }
975                 break;
976         default:
977                 printf ("(unknown return type %x)", 
978                         mono_method_signature (method)->ret->type);
979         }
980
981         ip = ((gint32) __builtin_return_address (0)) & 0x7fffffff;
982         printf (" ip: %p\n", ip);
983 }
984
985 /*========================= End of Function ========================*/
986
987 /*------------------------------------------------------------------*/
988 /*                                                                  */
989 /* Name         - mono_arch_cpu_init                                */
990 /*                                                                  */
991 /* Function     - Perform CPU specific initialization to execute    */
992 /*                managed code.                                     */
993 /*                                                                  */
994 /*------------------------------------------------------------------*/
995
996 void
997 mono_arch_cpu_init (void)
998 {
999         guint mode = 1;
1000
1001         /*--------------------------------------*/      
1002         /* Set default rounding mode for FP     */
1003         /*--------------------------------------*/      
1004         __asm__ ("SRNM\t%0\n\t"
1005                 : : "m" (mode));
1006 }
1007
1008 /*========================= End of Function ========================*/
1009
1010 /*------------------------------------------------------------------*/
1011 /*                                                                  */
1012 /* Name         - mono_arch_cpu_optimizazions                       */
1013 /*                                                                  */
1014 /* Function     - Returns the optimizations supported on this CPU   */
1015 /*                                                                  */
1016 /*------------------------------------------------------------------*/
1017
1018 guint32
1019 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
1020 {
1021         guint32 opts = 0;
1022
1023         /*----------------------------------------------------------*/
1024         /* no s390-specific optimizations yet                       */
1025         /*----------------------------------------------------------*/
1026         *exclude_mask = MONO_OPT_INLINE|MONO_OPT_LINEARS;
1027 //      *exclude_mask = MONO_OPT_INLINE;
1028         return opts;
1029 }
1030
1031 /*========================= End of Function ========================*/
1032
1033 /*------------------------------------------------------------------*/
1034 /*                                                                  */
1035 /* Name         -                                                   */
1036 /*                                                                  */
1037 /* Function     -                                                   */
1038 /*                                                                  */
1039 /*------------------------------------------------------------------*/
1040
1041 static gboolean
1042 is_regsize_var (MonoType *t) {
1043         if (t->byref)
1044                 return TRUE;
1045         switch (mono_type_get_underlying_type (t)->type) {
1046         case MONO_TYPE_I4:
1047         case MONO_TYPE_U4:
1048         case MONO_TYPE_I:
1049         case MONO_TYPE_U:
1050                 return TRUE;
1051         case MONO_TYPE_OBJECT:
1052         case MONO_TYPE_STRING:
1053         case MONO_TYPE_CLASS:
1054         case MONO_TYPE_SZARRAY:
1055         case MONO_TYPE_ARRAY:
1056                 return FALSE;
1057         case MONO_TYPE_VALUETYPE:
1058                 if (t->data.klass->enumtype)
1059                         return is_regsize_var (t->data.klass->enum_basetype);
1060                 return FALSE;
1061         }
1062         return FALSE;
1063 }
1064
1065 /*========================= End of Function ========================*/
1066
1067 /*------------------------------------------------------------------*/
1068 /*                                                                  */
1069 /* Name         - mono_arch_get_allocatable_int_vars                */
1070 /*                                                                  */
1071 /* Function     -                                                   */
1072 /*                                                                  */
1073 /*------------------------------------------------------------------*/
1074
1075 GList *
1076 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
1077 {
1078         GList *vars = NULL;
1079         int i;
1080
1081         for (i = 0; i < cfg->num_varinfo; i++) {
1082                 MonoInst *ins = cfg->varinfo [i];
1083                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
1084
1085                 /* unused vars */
1086                 if (vmv->range.first_use.abs_pos > vmv->range.last_use.abs_pos)
1087                         continue;
1088
1089                 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
1090                         continue;
1091
1092                 /* we can only allocate 32 bit values */
1093                 if (is_regsize_var (ins->inst_vtype)) {
1094                         g_assert (MONO_VARINFO (cfg, i)->reg == -1);
1095                         g_assert (i == vmv->idx);
1096                         vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
1097                 }
1098         }
1099
1100         return vars;
1101 }
1102
1103 /*========================= End of Function ========================*/
1104
1105 /*------------------------------------------------------------------*/
1106 /*                                                                  */
1107 /* Name         - mono_arch_global_int_regs                         */
1108 /*                                                                  */
1109 /* Function     - Return a list of usable integer registers.        */
1110 /*                                                                  */
1111 /*------------------------------------------------------------------*/
1112
1113 GList *
1114 mono_arch_get_global_int_regs (MonoCompile *cfg)
1115 {
1116         GList *regs = NULL;
1117         MonoMethodHeader *header;
1118         int i, top = 13;
1119
1120         header = mono_method_get_header (cfg->method);
1121         if ((cfg->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses)
1122                 cfg->frame_reg = s390_r11;
1123
1124         for (i = 8; i < top; ++i) {
1125                 if (cfg->frame_reg != i) 
1126                         regs = g_list_prepend (regs, GUINT_TO_POINTER (i));
1127         }
1128
1129         return regs;
1130 }
1131
1132 /*========================= End of Function ========================*/
1133
1134 /*------------------------------------------------------------------*/
1135 /*                                                                  */
1136 /* Name         -  mono_arch_flush_icache                           */
1137 /*                                                                  */
1138 /* Function     -  Flush the CPU icache.                            */
1139 /*                                                                  */
1140 /*------------------------------------------------------------------*/
1141
1142 void
1143 mono_arch_flush_icache (guint8 *code, gint size)
1144 {
1145 }
1146
1147 /*========================= End of Function ========================*/
1148
1149 /*------------------------------------------------------------------*/
1150 /*                                                                  */
1151 /* Name         - add_general                                       */
1152 /*                                                                  */
1153 /* Function     - Determine code and stack size incremements for a  */
1154 /*                parameter.                                        */
1155 /*                                                                  */
1156 /*------------------------------------------------------------------*/
1157
1158 static void inline
1159 add_general (guint *gr, size_data *sz, ArgInfo *ainfo, gboolean simple)
1160 {
1161         if (simple) {
1162                 if (*gr > S390_LAST_ARG_REG) {
1163                         sz->stack_size  = S390_ALIGN(sz->stack_size, sizeof(long));
1164                         ainfo->offset   = sz->stack_size;
1165                         ainfo->reg      = STK_BASE;
1166                         ainfo->regtype  = RegTypeBase;
1167                         sz->stack_size += sizeof(int);
1168                         sz->code_size  += 12;    
1169                 } else {
1170                         ainfo->reg      = *gr;
1171                         sz->code_size  += 8;    
1172                 }
1173         } else {
1174                 if (*gr > S390_LAST_ARG_REG - 1) {
1175                         sz->stack_size  = S390_ALIGN(sz->stack_size, S390_STACK_ALIGNMENT);
1176                         ainfo->offset   = sz->stack_size;
1177                         ainfo->reg      = STK_BASE;
1178                         ainfo->regtype  = RegTypeBase;
1179                         sz->stack_size += sizeof(long long);
1180                         sz->code_size  += 10;   
1181                 } else {
1182                         ainfo->reg      = *gr;
1183                         sz->code_size  += 8;
1184                 }
1185                 (*gr) ++;
1186         }
1187         (*gr) ++;
1188 }
1189
1190 /*========================= End of Function ========================*/
1191
1192 /*------------------------------------------------------------------*/
1193 /*                                                                  */
1194 /* Name         - add_float                                         */
1195 /*                                                                  */
1196 /* Function     - Determine code and stack size incremements for a  */
1197 /*                float parameter.                                  */
1198 /*                                                                  */
1199 /*------------------------------------------------------------------*/
1200
1201 static void inline
1202 add_float (guint *fr,  size_data *sz, ArgInfo *ainfo)
1203 {
1204         if ((*fr) <= S390_LAST_FPARG_REG) {
1205                 ainfo->regtype = RegTypeFP;
1206                 ainfo->reg     = *fr;
1207                 sz->code_size += 4;
1208                 (*fr) += 2;
1209         }
1210         else {
1211                 ainfo->offset   = sz->stack_size;
1212                 ainfo->reg      = STK_BASE;
1213                 ainfo->regtype  = RegTypeBase;
1214                 sz->code_size  += 4;
1215                 sz->stack_size += ainfo->size;
1216         }
1217 }
1218
1219 /*========================= End of Function ========================*/
1220
1221 /*------------------------------------------------------------------*/
1222 /*                                                                  */
1223 /* Name         - calculate_sizes                                   */
1224 /*                                                                  */
1225 /* Function     - Determine the amount of space required for code   */
1226 /*                and stack. In addition determine starting points  */
1227 /*                for stack-based parameters, and area for struct-  */
1228 /*                ures being returned on the stack.                 */
1229 /*                                                                  */
1230 /*------------------------------------------------------------------*/
1231
1232 static CallInfo *
1233 calculate_sizes (MonoMethodSignature *sig, size_data *sz, 
1234                  gboolean string_ctor)
1235 {
1236         guint i, fr, gr, size;
1237         int nParm = sig->hasthis + sig->param_count;
1238         guint32 simpletype, align;
1239         CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * nParm);
1240
1241         fr                = 0;
1242         gr                = s390_r2;
1243         nParm             = 0;
1244         cinfo->struct_ret = 0;
1245         sz->retStruct     = 0;
1246         sz->stack_size    = S390_MINIMAL_STACK_SIZE;
1247         sz->code_size     = 0;
1248         sz->local_size    = 0;
1249
1250         /*----------------------------------------------------------*/
1251         /* We determine the size of the return code/stack in case we*/
1252         /* need to reserve a register to be used to address a stack */
1253         /* area that the callee will use.                           */
1254         /*----------------------------------------------------------*/
1255
1256         simpletype = mono_type_get_underlying_type (sig->ret)->type;
1257 enum_retvalue:
1258         switch (simpletype) {
1259                 case MONO_TYPE_BOOLEAN:
1260                 case MONO_TYPE_I1:
1261                 case MONO_TYPE_U1:
1262                 case MONO_TYPE_I2:
1263                 case MONO_TYPE_U2:
1264                 case MONO_TYPE_CHAR:
1265                 case MONO_TYPE_I4:
1266                 case MONO_TYPE_U4:
1267                 case MONO_TYPE_I:
1268                 case MONO_TYPE_U:
1269                 case MONO_TYPE_CLASS:
1270                 case MONO_TYPE_OBJECT:
1271                 case MONO_TYPE_SZARRAY:
1272                 case MONO_TYPE_ARRAY:
1273                 case MONO_TYPE_PTR:
1274                 case MONO_TYPE_FNPTR:
1275                 case MONO_TYPE_STRING:
1276                         cinfo->ret.reg = s390_r2;
1277                         sz->code_size += 4;
1278                         break;
1279                 case MONO_TYPE_R4:
1280                 case MONO_TYPE_R8:
1281                         cinfo->ret.reg = s390_f0;
1282                         sz->code_size += 4;
1283                         break;
1284                 case MONO_TYPE_I8:
1285                 case MONO_TYPE_U8:
1286                         cinfo->ret.reg = s390_r2;
1287                         sz->code_size += 4;
1288                         break;
1289                 case MONO_TYPE_VALUETYPE: {
1290                         MonoClass *klass = mono_class_from_mono_type (sig->ret);
1291                         if (sig->ret->data.klass->enumtype) {
1292                                 simpletype = sig->ret->data.klass->enum_basetype->type;
1293                                 goto enum_retvalue;
1294                         }
1295                         if (sig->pinvoke)
1296                                 size = mono_class_native_size (klass, &align);
1297                         else
1298                                 size = mono_class_value_size (klass, &align);
1299         
1300                         cinfo->ret.reg    = s390_r2;
1301                         cinfo->struct_ret = 1;
1302                         cinfo->ret.size   = size;
1303                         cinfo->ret.vtsize = size;
1304                         cinfo->ret.offset = sz->stack_size;
1305                         sz->stack_size   += S390_ALIGN(size, align);
1306                         gr++;
1307                         break;
1308                 }
1309                 case MONO_TYPE_TYPEDBYREF:
1310                         size = sizeof (MonoTypedRef);
1311                         cinfo->ret.reg    = s390_r2;
1312                         cinfo->struct_ret = 1;
1313                         cinfo->ret.size   = size;
1314                         cinfo->ret.vtsize = size;
1315                         cinfo->ret.offset = sz->stack_size;
1316                         sz->stack_size   += S390_ALIGN(size, align);
1317                         gr++;
1318                         break;
1319                 case MONO_TYPE_VOID:
1320                         break;
1321                 default:
1322                         g_error ("Can't handle as return value 0x%x", sig->ret->type);
1323         }
1324
1325         if (sig->hasthis) {
1326                 add_general (&gr, sz, cinfo->args+nParm, TRUE);
1327                 cinfo->args[nParm].size = sizeof(gpointer);
1328                 nParm++;
1329         }
1330
1331         /*----------------------------------------------------------*/
1332         /* We determine the size of the parameter code and stack    */
1333         /* requirements by checking the types and sizes of the      */
1334         /* parameters.                                              */
1335         /*----------------------------------------------------------*/
1336
1337         for (i = 0; i < sig->param_count; ++i) {
1338                 /*--------------------------------------------------*/
1339                 /* Handle vararg type calls. All args are put on    */
1340                 /* the stack.                                       */
1341                 /*--------------------------------------------------*/
1342                 if ((sig->call_convention == MONO_CALL_VARARG) &&
1343                     (i == sig->sentinelpos)) {
1344                         gr = S390_LAST_ARG_REG + 1;
1345                         add_general (&gr, sz, &cinfo->sigCookie, TRUE);
1346                 }
1347
1348                 if (sig->params [i]->byref) {
1349                         add_general (&gr, sz, cinfo->args+nParm, TRUE);
1350                         cinfo->args[nParm].size = sizeof(gpointer);
1351                         nParm++;
1352                         continue;
1353                 }
1354                 simpletype = mono_type_get_underlying_type(sig->params [i])->type;
1355                 switch (simpletype) {
1356                 case MONO_TYPE_BOOLEAN:
1357                 case MONO_TYPE_I1:
1358                 case MONO_TYPE_U1:
1359                         cinfo->args[nParm].size = sizeof(char);
1360                         add_general (&gr, sz, cinfo->args+nParm, TRUE);
1361                         nParm++;
1362                         break;
1363                 case MONO_TYPE_I2:
1364                 case MONO_TYPE_U2:
1365                 case MONO_TYPE_CHAR:
1366                         cinfo->args[nParm].size = sizeof(short);
1367                         add_general (&gr, sz, cinfo->args+nParm, TRUE);
1368                         nParm++;
1369                         break;
1370                 case MONO_TYPE_I4:
1371                 case MONO_TYPE_U4:
1372                         cinfo->args[nParm].size = sizeof(int);
1373                         add_general (&gr, sz, cinfo->args+nParm, TRUE);
1374                         nParm++;
1375                         break;
1376                 case MONO_TYPE_I:
1377                 case MONO_TYPE_U:
1378                 case MONO_TYPE_PTR:
1379                 case MONO_TYPE_FNPTR:
1380                 case MONO_TYPE_CLASS:
1381                 case MONO_TYPE_OBJECT:
1382                 case MONO_TYPE_STRING:
1383                 case MONO_TYPE_SZARRAY:
1384                 case MONO_TYPE_ARRAY:
1385                         cinfo->args[nParm].size = sizeof(gpointer);
1386                         add_general (&gr, sz, cinfo->args+nParm, TRUE);
1387                         nParm++;
1388                         break;
1389                 case MONO_TYPE_I8:
1390                 case MONO_TYPE_U8:
1391                         cinfo->args[nParm].size = sizeof(long long);
1392                         add_general (&gr, sz, cinfo->args+nParm, FALSE);
1393                         nParm++;
1394                         break;
1395                 case MONO_TYPE_R4:
1396                         cinfo->args[nParm].size = sizeof(float);
1397                         add_float (&fr, sz, cinfo->args+nParm);
1398                         nParm++;
1399                         break;
1400                 case MONO_TYPE_R8:
1401                         cinfo->args[nParm].size = sizeof(double);
1402                         add_float (&fr, sz, cinfo->args+nParm);
1403                         nParm++;
1404                         break;
1405                 case MONO_TYPE_VALUETYPE: {
1406                         MonoMarshalType *info;
1407                         MonoClass *klass = mono_class_from_mono_type (sig->params [i]);
1408                         if (sig->pinvoke)
1409                                 size = mono_class_native_size (klass, &align);
1410                         else
1411                                 size = mono_class_value_size (klass, &align);
1412         
1413                         info = mono_marshal_load_type_info (klass);
1414
1415                         if ((info->native_size == sizeof(float)) &&
1416                             (info->num_fields  == 1) &&
1417                             (info->fields[0].field->type->type == MONO_TYPE_R4)) {
1418                                 cinfo->args[nParm].size = sizeof(float);
1419                                 add_float(&fr, sz, cinfo->args+nParm);
1420                                 break;
1421                         }
1422
1423                         if ((info->native_size == sizeof(double)) &&
1424                             (info->num_fields  == 1) &&
1425                             (info->fields[0].field->type->type == MONO_TYPE_R8)) {
1426                                 cinfo->args[nParm].size = sizeof(double);
1427                                 add_float(&fr, sz, cinfo->args+nParm);
1428                                 break;
1429                         }
1430
1431                         cinfo->args[nParm].vtsize  = 0;
1432                         cinfo->args[nParm].size    = 0;
1433                         cinfo->args[nParm].offparm = sz->local_size;
1434
1435                         switch (size) {
1436                                 /*----------------------------------*/
1437                                 /* On S/390, structures of size 1,  */
1438                                 /* 2, 4, and 8 bytes are passed in  */
1439                                 /* (a) register(s).                 */
1440                                 /*----------------------------------*/
1441                                 case 0:
1442                                 case 1:
1443                                 case 2:
1444                                 case 4:
1445                                         add_general(&gr, sz, cinfo->args+nParm, TRUE);
1446                                         cinfo->args[nParm].size    = size;
1447                                         cinfo->args[nParm].regtype = RegTypeStructByVal; 
1448                                         nParm++;
1449                                         sz->local_size            += sizeof(long);
1450                                         break;
1451                                 case 8:
1452                                         add_general(&gr, sz, cinfo->args+nParm, FALSE);
1453                                         cinfo->args[nParm].size    = sizeof(long long);
1454                                         cinfo->args[nParm].regtype = RegTypeStructByVal; 
1455                                         nParm++;
1456                                         sz->local_size            += sizeof(long);
1457                                         break;
1458                                 default:
1459                                         add_general(&gr, sz, cinfo->args+nParm, TRUE);
1460                                         cinfo->args[nParm].size    = sizeof(int);
1461                                         cinfo->args[nParm].regtype = RegTypeStructByAddr; 
1462                                         cinfo->args[nParm].vtsize  = size;
1463                                         sz->code_size             += 40;
1464                                         sz->local_size            += size;
1465                                         if (cinfo->args[nParm].reg == STK_BASE)
1466                                                 sz->local_size += sizeof(gpointer);
1467                                         nParm++;
1468                         }
1469                 }
1470                         break;
1471                 case MONO_TYPE_TYPEDBYREF: {
1472                         int size = sizeof (MonoTypedRef);
1473
1474                         cinfo->args[nParm].vtsize  = 0;
1475                         cinfo->args[nParm].size    = 0;
1476                         cinfo->args[nParm].offparm = sz->local_size;
1477
1478                         switch (size) {
1479                                 /*----------------------------------*/
1480                                 /* On S/390, structures of size 1,  */
1481                                 /* 2, 4, and 8 bytes are passed in  */
1482                                 /* (a) register(s).                 */
1483                                 /*----------------------------------*/
1484                                 case 0:
1485                                 case 1:
1486                                 case 2:
1487                                 case 4:
1488                                         add_general(&gr, sz, cinfo->args+nParm, TRUE);
1489                                         cinfo->args[nParm].size    = size;
1490                                         cinfo->args[nParm].regtype = RegTypeStructByVal; 
1491                                         nParm++;
1492                                         sz->local_size            += sizeof(long);
1493                                         break;
1494                                 case 8:
1495                                         add_general(&gr, sz, cinfo->args+nParm, FALSE);
1496                                         cinfo->args[nParm].size    = sizeof(long long);
1497                                         cinfo->args[nParm].regtype = RegTypeStructByVal; 
1498                                         nParm++;
1499                                         sz->local_size            += sizeof(long);
1500                                         break;
1501                                 default:
1502                                         add_general(&gr, sz, cinfo->args+nParm, TRUE);
1503                                         cinfo->args[nParm].size    = sizeof(int);
1504                                         cinfo->args[nParm].regtype = RegTypeStructByAddr; 
1505                                         cinfo->args[nParm].vtsize  = size;
1506                                         sz->code_size             += 40;
1507                                         sz->local_size            += size;
1508                                         if (cinfo->args[nParm].reg == STK_BASE)
1509                                                 sz->local_size += sizeof(gpointer);
1510                                         nParm++;
1511                         }
1512                 }
1513                         break;
1514                 default:
1515                         g_error ("Can't trampoline 0x%x", sig->params [i]->type);
1516                 }
1517         }
1518
1519         cinfo->stack_usage = S390_ALIGN(sz->stack_size+sz->local_size, 
1520                                         S390_STACK_ALIGNMENT);
1521         return (cinfo);
1522 }
1523
1524 /*========================= End of Function ========================*/
1525
1526 /*------------------------------------------------------------------*/
1527 /*                                                                  */
1528 /* Name         - mono_arch_allocate_vars                           */
1529 /*                                                                  */
1530 /* Function     - Set var information according to the calling      */
1531 /*                convention for S/390. The local var stuff should  */
1532 /*                most likely be split in another method.           */
1533 /*                                                                  */
1534 /* Parameter    - @m - Compile unit.                                */
1535 /*                                                                  */
1536 /*------------------------------------------------------------------*/
1537
1538 void
1539 mono_arch_allocate_vars (MonoCompile *cfg)
1540 {
1541         MonoMethodSignature *sig;
1542         MonoMethodHeader *header;
1543         MonoInst *inst;
1544         CallInfo *cinfo;
1545         size_data sz;
1546         int iParm, iVar, offset, size, align, curinst;
1547         int frame_reg = STK_BASE;
1548         int sArg, eArg;
1549
1550         header  = mono_method_get_header (cfg->method);
1551
1552         /*---------------------------------------------------------*/    
1553         /* We use the frame register also for any method that has  */ 
1554         /* filter clauses. This way, when the handlers are called, */
1555         /* the code will reference local variables using the frame */
1556         /* reg instead of the stack pointer: if we had to restore  */
1557         /* the stack pointer, we'd corrupt the method frames that  */
1558         /* are already on the stack (since filters get called      */
1559         /* before stack unwinding happens) when the filter code    */
1560         /* would call any method.                                  */
1561         /*---------------------------------------------------------*/    
1562         if ((cfg->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses)
1563                 frame_reg = s390_r11;
1564
1565         cfg->frame_reg = frame_reg;
1566
1567         if (frame_reg != STK_BASE) 
1568                 cfg->used_int_regs |= 1 << frame_reg;           
1569
1570         sig     = mono_method_signature (cfg->method);
1571         
1572         cinfo   = calculate_sizes (sig, &sz, sig->pinvoke);
1573
1574         if (cinfo->struct_ret) {
1575                 cfg->ret->opcode = OP_REGVAR;
1576                 cfg->ret->inst_c0 = s390_r2;
1577         } else {
1578                 switch (mono_type_get_underlying_type (sig->ret)->type) {
1579                 case MONO_TYPE_VOID:
1580                         break;
1581                 default:
1582                         cfg->ret->opcode = OP_REGVAR;
1583                         cfg->ret->dreg   = s390_r2;
1584                         break;
1585                 }
1586         }
1587
1588         /*--------------------------------------------------------------*/
1589         /* local vars are at a positive offset from the stack pointer   */
1590         /* also note that if the function uses alloca, we use s390_r11  */
1591         /* to point at the local variables.                             */
1592         /* add parameter area size for called functions                 */
1593         /*--------------------------------------------------------------*/
1594         offset          = (cfg->param_area + S390_MINIMAL_STACK_SIZE);
1595         cfg->sig_cookie = 0;
1596
1597         if (cinfo->struct_ret) {
1598                 inst               = cfg->ret;
1599                 offset             = S390_ALIGN(offset, sizeof(gpointer));
1600                 inst->inst_offset  = offset;
1601                 inst->opcode       = OP_REGOFFSET;
1602                 inst->inst_basereg = frame_reg;
1603                 offset            += sizeof(gpointer);
1604                 if ((sig->call_convention == MONO_CALL_VARARG) &&
1605                     (!retFitsInReg (cinfo->ret.size)))
1606                         cfg->sig_cookie += cinfo->ret.size;
1607         }
1608
1609         if (sig->hasthis) {
1610                 inst = cfg->varinfo [0];
1611                 if (inst->opcode != OP_REGVAR) {
1612                         inst->opcode       = OP_REGOFFSET;
1613                         inst->inst_basereg = frame_reg;
1614                         offset             = S390_ALIGN(offset, sizeof(gpointer));
1615                         inst->inst_offset  = offset;
1616                         offset            += sizeof (gpointer);
1617                 }
1618                 curinst = sArg = 1;
1619         } else {
1620                 curinst = sArg = 0;
1621         }
1622
1623         eArg = sig->param_count + sArg;
1624
1625         if (sig->call_convention == MONO_CALL_VARARG)
1626                 cfg->sig_cookie += S390_MINIMAL_STACK_SIZE;
1627
1628         for (iParm = sArg; iParm < eArg; ++iParm) {
1629                 inst = cfg->varinfo [curinst];
1630                 if (inst->opcode != OP_REGVAR) {
1631                         switch (cinfo->args[iParm].regtype) {
1632                                 case RegTypeStructByAddr :
1633                                         inst->opcode       = OP_S390_LOADARG;
1634                                         inst->inst_basereg = frame_reg;
1635                                         size               = abs(cinfo->args[iParm].vtsize);
1636                                         offset             = S390_ALIGN(offset, size);
1637                                         inst->inst_offset  = offset; 
1638                                         break;
1639                                 case RegTypeStructByVal :
1640                                         inst->opcode       = OP_S390_ARGPTR;
1641                                         inst->inst_basereg = frame_reg;
1642                                         size               = cinfo->args[iParm].size;
1643                                         offset             = S390_ALIGN(offset, size);
1644                                         inst->inst_offset  = offset;
1645                                         break;
1646                                 default :
1647                                 if (cinfo->args[iParm].reg != STK_BASE) {
1648                                         inst->opcode       = OP_REGOFFSET;
1649                                         inst->inst_basereg = frame_reg;
1650                                         size               = (cinfo->args[iParm].size < 8
1651                                                               ? sizeof(long)  
1652                                                               : sizeof(long long));
1653                                         offset             = S390_ALIGN(offset, size);
1654                                         inst->inst_offset  = offset;
1655                                 } else {
1656                                         inst->opcode       = OP_S390_STKARG;
1657                                         inst->inst_basereg = frame_reg;
1658                                         size               = (cinfo->args[iParm].size < 4
1659                                                               ? 4 - cinfo->args[iParm].size
1660                                                               : 0);
1661                                         inst->inst_offset  = cinfo->args[iParm].offset + 
1662                                                              size;
1663                                         inst->unused       = 0;
1664                                         size               = sizeof(long);
1665                                 } 
1666                         }
1667                         if ((sig->call_convention == MONO_CALL_VARARG) && 
1668                             (cinfo->args[iParm].regtype != RegTypeGeneral) &&
1669                             (iParm < sig->sentinelpos)) 
1670                                 cfg->sig_cookie += size;
1671
1672                         offset += size;
1673                 }
1674                 curinst++;
1675         }
1676
1677         curinst = cfg->locals_start;
1678         for (iVar = curinst; iVar < cfg->num_varinfo; ++iVar) {
1679                 inst = cfg->varinfo [iVar];
1680                 if ((inst->flags & MONO_INST_IS_DEAD) || 
1681                     (inst->opcode == OP_REGVAR))
1682                         continue;
1683
1684                 /*--------------------------------------------------*/
1685                 /* inst->unused indicates native sized value types, */
1686                 /* this is used by the pinvoke wrappers when they   */
1687                 /* call functions returning structure               */
1688                 /*--------------------------------------------------*/
1689                 if (inst->unused && MONO_TYPE_ISSTRUCT (inst->inst_vtype))
1690                         size = mono_class_native_size (mono_class_from_mono_type(inst->inst_vtype), &align);
1691                 else
1692                         size = mono_type_size (inst->inst_vtype, &align);
1693
1694                 offset             = S390_ALIGN(offset, align);
1695                 inst->inst_offset  = offset;
1696                 inst->opcode       = OP_REGOFFSET;
1697                 inst->inst_basereg = frame_reg;
1698                 offset            += size;
1699                 DEBUG (g_print("allocating local %d to %d\n", iVar, inst->inst_offset));
1700         }
1701
1702         /*------------------------------------------------------*/
1703         /* Allow space for the trace method stack area if needed*/
1704         /*------------------------------------------------------*/
1705         if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg)) 
1706                 offset += S390_TRACE_STACK_SIZE;
1707
1708         /*------------------------------------------------------*/
1709         /* Reserve space to save LMF and caller saved registers */
1710         /*------------------------------------------------------*/
1711         if (cfg->method->save_lmf)
1712                 offset += sizeof (MonoLMF);
1713
1714         /*------------------------------------------------------*/
1715         /* align the offset                                     */
1716         /*------------------------------------------------------*/
1717         cfg->stack_offset = S390_ALIGN(offset, S390_STACK_ALIGNMENT);
1718
1719 }
1720
1721 /*========================= End of Function ========================*/
1722
1723 /*------------------------------------------------------------------*/
1724 /*                                                                  */
1725 /* Name         - mono_arch_call_opcode                             */
1726 /*                                                                  */
1727 /* Function     - Take the arguments and generate the arch-specific */
1728 /*                instructions to properly call the function. This  */
1729 /*                includes pushing, moving argments to the correct  */
1730 /*                etc.                                              */
1731 /*                                                                  */
1732 /* Note         - FIXME: We need an alignment solution for          */
1733 /*                enter_method and mono_arch_call_opcode, currently */
1734 /*                alignment in mono_arch_call_opcode is computed    */
1735 /*                without arch_get_argument_info.                   */
1736 /*                                                                  */
1737 /*------------------------------------------------------------------*/
1738
1739 MonoCallInst*
1740 mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, 
1741                        MonoCallInst *call, int is_virtual) {
1742         MonoInst *arg, *in;
1743         MonoMethodSignature *sig;
1744         int i, n, lParamArea;
1745         CallInfo *cinfo;
1746         ArgInfo *ainfo;
1747         size_data sz;
1748
1749         sig = call->signature;
1750         n = sig->param_count + sig->hasthis;
1751         DEBUG (g_print ("Call requires: %d parameters\n",n));
1752         
1753         cinfo = calculate_sizes (sig, &sz, sig->pinvoke);
1754
1755         call->stack_usage = cinfo->stack_usage;
1756         lParamArea        = MAX((cinfo->stack_usage - S390_MINIMAL_STACK_SIZE), 0);
1757         cfg->param_area   = MAX (((signed) cfg->param_area), lParamArea);
1758         cfg->flags       |= MONO_CFG_HAS_CALLS;
1759
1760         if (cinfo->struct_ret)
1761                 call->used_iregs |= 1 << cinfo->ret.reg;
1762
1763         for (i = 0; i < n; ++i) {
1764                 ainfo = cinfo->args + i;
1765
1766                 if ((sig->call_convention == MONO_CALL_VARARG) &&
1767                     (i == sig->sentinelpos)) {
1768                         MonoInst *sigArg;
1769                         
1770                         cfg->disable_aot = TRUE;
1771                         MONO_INST_NEW (cfg, sigArg, OP_ICONST);
1772                         sigArg->inst_p0 = call->signature;
1773
1774                         MONO_INST_NEW (cfg, arg, OP_OUTARG);
1775                         arg->inst_imm  = cinfo->sigCookie.offset;
1776                         arg->inst_left = sigArg;
1777
1778                         arg->next      = call->out_args;
1779                         call->out_args = arg;
1780                 }
1781
1782                 if (is_virtual && i == 0) {
1783                         /* the argument will be attached to the call instrucion */
1784                         in = call->args [i];
1785                         call->used_iregs |= 1 << ainfo->reg;
1786                 } else {
1787                         MONO_INST_NEW (cfg, arg, OP_OUTARG);
1788                         in = call->args [i];
1789                         arg->cil_code  = in->cil_code;
1790                         arg->inst_left = in;
1791                         arg->type      = in->type;
1792                         /* prepend, we'll need to reverse them later */
1793                         arg->next      = call->out_args;
1794                         call->out_args = arg;
1795                         if (ainfo->regtype == RegTypeGeneral) {
1796                                 arg->unused = ainfo->reg;
1797                                 call->used_iregs |= 1 << ainfo->reg;
1798                                 if (arg->type == STACK_I8)
1799                                         call->used_iregs |= 1 << (ainfo->reg + 1);
1800                         } else if (ainfo->regtype == RegTypeStructByAddr) {
1801                                 call->used_iregs |= 1 << ainfo->reg;
1802                                 arg->sreg1     = ainfo->reg;
1803                                 arg->opcode    = OP_OUTARG_VT;
1804                                 arg->unused    = -ainfo->vtsize;
1805                                 arg->inst_imm  = ainfo->offset;
1806                                 arg->sreg2     = ainfo->offparm + S390_MINIMAL_STACK_SIZE;
1807                         } else if (ainfo->regtype == RegTypeStructByVal) {
1808                                 if (ainfo->reg != STK_BASE) {
1809                                         switch (ainfo->size) {
1810                                         case 0:
1811                                         case 1:
1812                                         case 2:
1813                                         case 4:
1814                                                 call->used_iregs |= 1 << ainfo->reg;
1815                                                 break;
1816                                         case 8:
1817                                                 call->used_iregs |= 1 << ainfo->reg;
1818                                                 call->used_iregs |= 1 << (ainfo->reg+1);
1819                                                 break;
1820                                         default:
1821                                                 call->used_iregs |= 1 << ainfo->reg;
1822                                         }
1823                                 } 
1824                                 arg->sreg1     = ainfo->reg;
1825                                 arg->opcode    = OP_OUTARG_VT;
1826                                 arg->unused    = ainfo->size;
1827                                 arg->inst_imm  = ainfo->offset;
1828                                 arg->sreg2     = ainfo->offparm + S390_MINIMAL_STACK_SIZE;
1829                         } else if (ainfo->regtype == RegTypeBase) {
1830                                 arg->opcode = OP_OUTARG;
1831                                 arg->unused = ainfo->reg | (ainfo->size << 8);
1832                                 arg->inst_imm = ainfo->offset;
1833                                 call->used_fregs |= 1 << ainfo->reg;
1834                         } else if (ainfo->regtype == RegTypeFP) {
1835                                 arg->unused = ainfo->reg;
1836                                 call->used_fregs |= 1 << ainfo->reg;
1837                                 if (ainfo->size == 4) {
1838                                         MonoInst *conv;
1839                                         arg->opcode     = OP_OUTARG_R4;
1840                                         MONO_INST_NEW (cfg, conv, OP_FCONV_TO_R4);
1841                                         conv->inst_left = arg->inst_left;
1842                                         arg->inst_left  = conv;
1843                                 }
1844                                 else
1845                                         arg->opcode = OP_OUTARG_R8;
1846                         } else {
1847                                 g_assert_not_reached ();
1848                         }
1849                 }
1850         }
1851         /*
1852          * Reverse the call->out_args list.
1853          */
1854         {
1855                 MonoInst *prev = NULL, *list = call->out_args, *next;
1856                 while (list) {
1857                         next = list->next;
1858                         list->next = prev;
1859                         prev = list;
1860                         list = next;
1861                 }
1862                 call->out_args = prev;
1863         }
1864
1865         g_free (cinfo);
1866         return call;
1867 }
1868
1869 /*========================= End of Function ========================*/
1870
1871 /*------------------------------------------------------------------*/
1872 /*                                                                  */
1873 /* Name         - mono_arch_instrument_mem_needs                    */
1874 /*                                                                  */
1875 /* Function     - Allow tracing to work with this interface (with   */
1876 /*                an optional argument).                            */
1877 /*                                                                  */
1878 /*------------------------------------------------------------------*/
1879
1880 void
1881 mono_arch_instrument_mem_needs (MonoMethod *method, int *stack, int *code)
1882 {
1883         /* no stack room needed now (may be needed for FASTCALL-trace support) */
1884         *stack = 0;
1885         /* split prolog-epilog requirements? */
1886         *code = 50; /* max bytes needed: check this number */
1887 }
1888
1889 /*========================= End of Function ========================*/
1890
1891 /*------------------------------------------------------------------*/
1892 /*                                                                  */
1893 /* Name         - mono_arch_instrument_prolog                       */
1894 /*                                                                  */
1895 /* Function     - Create an "instrumented" prolog.                  */
1896 /*                                                                  */
1897 /*------------------------------------------------------------------*/
1898
1899 void*
1900 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, 
1901                              gboolean enable_arguments)
1902 {
1903         guchar *code = p;
1904         int     parmOffset, 
1905                 fpOffset;
1906
1907         parmOffset = cfg->stack_usage - S390_TRACE_STACK_SIZE;
1908         if (cfg->method->save_lmf)
1909                 parmOffset -= sizeof(MonoLMF);
1910         fpOffset   = parmOffset + (5*sizeof(gint32));
1911
1912         s390_stm  (code, s390_r2, s390_r6, STK_BASE, parmOffset);
1913         s390_std  (code, s390_f0, 0, STK_BASE, fpOffset);
1914         s390_std  (code, s390_f1, 0, STK_BASE, fpOffset+sizeof(gdouble));
1915         s390_std  (code, s390_f2, 0, STK_BASE, fpOffset+2*sizeof(gdouble));
1916         s390_basr (code, s390_r13, 0);
1917         s390_j    (code, 6);
1918         s390_word (code, cfg->method);
1919         s390_word (code, func);
1920         s390_l    (code, s390_r2, 0, s390_r13, 4);
1921         s390_la   (code, s390_r3, 0, STK_BASE, parmOffset);
1922         s390_lr   (code, s390_r4, STK_BASE);
1923         s390_ahi  (code, s390_r4, cfg->stack_usage);
1924         s390_l    (code, s390_r1, 0, s390_r13, 8);
1925         s390_basr (code, s390_r14, s390_r1);
1926         s390_ld   (code, s390_f2, 0, STK_BASE, fpOffset+2*sizeof(gdouble));
1927         s390_ld   (code, s390_f1, 0, STK_BASE, fpOffset+sizeof(gdouble));
1928         s390_ld   (code, s390_f0, 0, STK_BASE, fpOffset);
1929         s390_lm   (code, s390_r2, s390_r6, STK_BASE, parmOffset);
1930
1931         return code;
1932 }
1933
1934 /*========================= End of Function ========================*/
1935
1936 /*------------------------------------------------------------------*/
1937 /*                                                                  */
1938 /* Name         - mono_arch_instrument_epilog                       */
1939 /*                                                                  */
1940 /* Function     - Create an epilog that will handle the returned    */
1941 /*                values used in instrumentation.                   */
1942 /*                                                                  */
1943 /*------------------------------------------------------------------*/
1944
1945 void*
1946 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1947 {
1948         guchar     *code = p;
1949         int        save_mode = SAVE_NONE,
1950                    saveOffset;
1951         MonoMethod *method = cfg->method;
1952         int        rtype = mono_type_get_underlying_type (mono_method_signature (method)->ret)->type;
1953
1954         saveOffset = cfg->stack_usage - S390_TRACE_STACK_SIZE;
1955         if (method->save_lmf)
1956                 saveOffset -= sizeof(MonoLMF);
1957
1958 handle_enum:
1959         switch (rtype) {
1960         case MONO_TYPE_VOID:
1961                 /* special case string .ctor icall */
1962                 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
1963                         save_mode = SAVE_ONE;
1964                 else
1965                         save_mode = SAVE_NONE;
1966                 break;
1967         case MONO_TYPE_I8:
1968         case MONO_TYPE_U8:
1969                 save_mode = SAVE_TWO;
1970                 break;
1971         case MONO_TYPE_R4:
1972         case MONO_TYPE_R8:
1973                 save_mode = SAVE_FP;
1974                 break;
1975         case MONO_TYPE_VALUETYPE:
1976                 if (mono_method_signature (method)->ret->data.klass->enumtype) {
1977                         rtype = mono_method_signature (method)->ret->data.klass->enum_basetype->type;
1978                         goto handle_enum;
1979                 }
1980                 save_mode = SAVE_STRUCT;
1981                 break;
1982         default:
1983                 save_mode = SAVE_ONE;
1984                 break;
1985         }
1986
1987         switch (save_mode) {
1988         case SAVE_TWO:
1989                 s390_stm (code, s390_r2, s390_r3, cfg->frame_reg, saveOffset);
1990                 if (enable_arguments) {
1991                         s390_lr (code, s390_r4, s390_r3);
1992                         s390_lr (code, s390_r3, s390_r2);
1993                 }
1994                 break;
1995         case SAVE_ONE:
1996                 s390_st (code, s390_r2, 0, cfg->frame_reg, saveOffset);
1997                 if (enable_arguments) {
1998                         s390_lr (code, s390_r3, s390_r2);
1999                 }
2000                 break;
2001         case SAVE_FP:
2002                 s390_std (code, s390_f0, 0, cfg->frame_reg, saveOffset);
2003                 if (enable_arguments) {
2004                         /* FIXME: what reg?  */
2005                         s390_ldr (code, s390_f2, s390_f0);
2006                         s390_lm  (code, s390_r3, s390_r4, cfg->frame_reg, saveOffset);
2007                 }
2008                 break;
2009         case SAVE_STRUCT:
2010                 s390_st (code, s390_r2, 0, cfg->frame_reg, saveOffset);
2011                 if (enable_arguments) {
2012                         s390_l (code, s390_r3, 0, cfg->frame_reg, 
2013                                 S390_MINIMAL_STACK_SIZE+cfg->param_area);
2014                 }
2015                 break;
2016         case SAVE_NONE:
2017         default:
2018                 break;
2019         }
2020
2021         s390_basr (code, s390_r13, 0);
2022         s390_j    (code, 6);
2023         s390_word (code, cfg->method);
2024         s390_word (code, func);
2025         s390_l    (code, s390_r2, 0, s390_r13, 4);
2026         s390_l    (code, s390_r1, 0, s390_r13, 8);
2027         s390_basr (code, s390_r14, s390_r1);
2028
2029         switch (save_mode) {
2030         case SAVE_TWO:
2031                 s390_lm  (code, s390_r2, s390_r3, cfg->frame_reg, saveOffset);
2032                 break;
2033         case SAVE_ONE:
2034                 s390_l   (code, s390_r2, 0, cfg->frame_reg, saveOffset);
2035                 break;
2036         case SAVE_FP:
2037                 s390_ld  (code, s390_f0, 0, cfg->frame_reg, saveOffset);
2038                 break;
2039         case SAVE_STRUCT:
2040                 s390_l   (code, s390_r2, 0, cfg->frame_reg, saveOffset);
2041                 break;
2042         case SAVE_NONE:
2043         default:
2044                 break;
2045         }
2046
2047         return code;
2048 }
2049
2050 /*========================= End of Function ========================*/
2051
2052 /*------------------------------------------------------------------*/
2053 /*                                                                  */
2054 /* Name         - peephole_pass                                     */
2055 /*                                                                  */
2056 /* Function     - Form a peephole pass at the code looking for      */
2057 /*                simple optimizations.                             */
2058 /*                                                                  */
2059 /*------------------------------------------------------------------*/
2060
2061 static void
2062 peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2063 {
2064         MonoInst *ins, *last_ins = NULL;
2065         ins = bb->code;
2066
2067         while (ins) {
2068
2069                 switch (ins->opcode) {
2070                 case OP_MUL_IMM: 
2071                         /* remove unnecessary multiplication with 1 */
2072                         if (ins->inst_imm == 1) {
2073                                 if (ins->dreg != ins->sreg1) {
2074                                         ins->opcode = OP_MOVE;
2075                                 } else {
2076                                         last_ins->next = ins->next;                             
2077                                         ins = ins->next;                                
2078                                         continue;
2079                                 }
2080                         }
2081                         break;
2082                 case OP_LOAD_MEMBASE:
2083                 case OP_LOADI4_MEMBASE:
2084                         /* 
2085                          * OP_STORE_MEMBASE_REG reg, offset(basereg) 
2086                          * OP_LOAD_MEMBASE offset(basereg), reg
2087                          */
2088                         if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG 
2089                                          || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
2090                             ins->inst_basereg == last_ins->inst_destbasereg &&
2091                             ins->inst_offset == last_ins->inst_offset) {
2092                                 if (ins->dreg == last_ins->sreg1) {
2093                                         last_ins->next = ins->next;                             
2094                                         ins = ins->next;                                
2095                                         continue;
2096                                 } else {
2097                                         //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2098                                         ins->opcode = OP_MOVE;
2099                                         ins->sreg1 = last_ins->sreg1;
2100                                 }
2101
2102                         /* 
2103                          * Note: reg1 must be different from the basereg in the second load
2104                          * OP_LOAD_MEMBASE offset(basereg), reg1
2105                          * OP_LOAD_MEMBASE offset(basereg), reg2
2106                          * -->
2107                          * OP_LOAD_MEMBASE offset(basereg), reg1
2108                          * OP_MOVE reg1, reg2
2109                          */
2110                         } if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
2111                                            || last_ins->opcode == OP_LOAD_MEMBASE) &&
2112                               ins->inst_basereg != last_ins->dreg &&
2113                               ins->inst_basereg == last_ins->inst_basereg &&
2114                               ins->inst_offset == last_ins->inst_offset) {
2115
2116                                 if (ins->dreg == last_ins->dreg) {
2117                                         last_ins->next = ins->next;                             
2118                                         ins = ins->next;                                
2119                                         continue;
2120                                 } else {
2121                                         ins->opcode = OP_MOVE;
2122                                         ins->sreg1 = last_ins->dreg;
2123                                 }
2124
2125                                 //g_assert_not_reached ();
2126
2127 #if 0
2128                         /* 
2129                          * OP_STORE_MEMBASE_IMM imm, offset(basereg) 
2130                          * OP_LOAD_MEMBASE offset(basereg), reg
2131                          * -->
2132                          * OP_STORE_MEMBASE_IMM imm, offset(basereg) 
2133                          * OP_ICONST reg, imm
2134                          */
2135                         } else if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
2136                                                 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
2137                                    ins->inst_basereg == last_ins->inst_destbasereg &&
2138                                    ins->inst_offset == last_ins->inst_offset) {
2139                                 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2140                                 ins->opcode = OP_ICONST;
2141                                 ins->inst_c0 = last_ins->inst_imm;
2142                                 g_assert_not_reached (); // check this rule
2143 #endif
2144                         }
2145                         break;
2146                 case OP_LOADU1_MEMBASE:
2147                 case OP_LOADI1_MEMBASE:
2148                         if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
2149                                         ins->inst_basereg == last_ins->inst_destbasereg &&
2150                                         ins->inst_offset == last_ins->inst_offset) {
2151                                 if (ins->dreg == last_ins->sreg1) {
2152                                         last_ins->next = ins->next;                             
2153                                         ins = ins->next;                                
2154                                         continue;
2155                                 } else {
2156                                         //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2157                                         ins->opcode = OP_MOVE;
2158                                         ins->sreg1 = last_ins->sreg1;
2159                                 }
2160                         }
2161                         break;
2162                 case OP_LOADU2_MEMBASE:
2163                 case OP_LOADI2_MEMBASE:
2164                         if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
2165                                         ins->inst_basereg == last_ins->inst_destbasereg &&
2166                                         ins->inst_offset == last_ins->inst_offset) {
2167                                 if (ins->dreg == last_ins->sreg1) {
2168                                         last_ins->next = ins->next;                             
2169                                         ins = ins->next;                                
2170                                         continue;
2171                                 } else {
2172                                         ins->opcode = OP_MOVE;
2173                                         ins->sreg1 = last_ins->sreg1;
2174                                 }
2175                         }
2176                         break;
2177                 case CEE_CONV_I4:
2178                 case CEE_CONV_U4:
2179                 case OP_MOVE:
2180                         /* 
2181                          * OP_MOVE reg, reg 
2182                          */
2183                         if (ins->dreg == ins->sreg1) {
2184                                 if (last_ins)
2185                                         last_ins->next = ins->next;                             
2186                                 ins = ins->next;
2187                                 continue;
2188                         }
2189                         /* 
2190                          * OP_MOVE sreg, dreg 
2191                          * OP_MOVE dreg, sreg
2192                          */
2193                         if (last_ins && last_ins->opcode == OP_MOVE &&
2194                             ins->sreg1 == last_ins->dreg &&
2195                             ins->dreg == last_ins->sreg1) {
2196                                 last_ins->next = ins->next;                             
2197                                 ins = ins->next;                                
2198                                 continue;
2199                         }
2200                         break;
2201                 }
2202                 last_ins = ins;
2203                 ins = ins->next;
2204         }
2205         bb->last_ins = last_ins;
2206 }
2207
2208 /*========================= End of Function ========================*/
2209
2210 /*------------------------------------------------------------------*/
2211 /*                                                                  */
2212 /* Name         - mono_spillvar_offset                              */
2213 /*                                                                  */
2214 /* Function     - Returns the offset used by spillvar. It allocates */
2215 /*                a new spill variable if necessary.                */
2216 /*                                                                  */
2217 /*------------------------------------------------------------------*/
2218
2219 static int
2220 mono_spillvar_offset (MonoCompile *cfg, int spillvar)
2221 {
2222         MonoSpillInfo **si, *info;
2223         int i = 0;
2224
2225         si = &cfg->spill_info; 
2226         
2227         while (i <= spillvar) {
2228
2229                 if (!*si) {
2230                         *si = info = mono_mempool_alloc (cfg->mempool, sizeof (MonoSpillInfo));
2231                         info->next = NULL;
2232                         info->offset = cfg->stack_offset;
2233                         cfg->stack_offset += sizeof (gpointer);
2234                 }
2235
2236                 if (i == spillvar)
2237                         return (*si)->offset;
2238
2239                 i++;
2240                 si = &(*si)->next;
2241         }
2242
2243         g_assert_not_reached ();
2244         return 0;
2245 }
2246
2247 /*========================= End of Function ========================*/
2248
2249 /*------------------------------------------------------------------*/
2250 /*                                                                  */
2251 /* Name         - mono_spillvar_offset_float                        */
2252 /*                                                                  */
2253 /* Function     -                                                   */
2254 /*                                                                  */
2255 /*------------------------------------------------------------------*/
2256
2257 static int
2258 mono_spillvar_offset_float (MonoCompile *cfg, int spillvar)
2259 {
2260         MonoSpillInfo **si, *info;
2261         int i = 0;
2262
2263         si = &cfg->spill_info_float; 
2264         
2265         while (i <= spillvar) {
2266
2267                 if (!*si) {
2268                         *si = info = mono_mempool_alloc (cfg->mempool, sizeof (MonoSpillInfo));
2269                         info->next         = NULL;
2270                         cfg->stack_offset  = S390_ALIGN(cfg->stack_offset, S390_STACK_ALIGNMENT);
2271                         info->offset       = cfg->stack_offset;
2272                         cfg->stack_offset += sizeof (double);
2273                 }
2274
2275                 if (i == spillvar)
2276                         return (*si)->offset;
2277
2278                 i++;
2279                 si = &(*si)->next;
2280         }
2281
2282         g_assert_not_reached ();
2283         return 0;
2284 }
2285
2286 /*========================= End of Function ========================*/
2287
2288 /*------------------------------------------------------------------*/
2289 /*                                                                  */
2290 /* Name         - print_ins                                         */
2291 /*                                                                  */
2292 /* Function     - Decode and print the instruction for tracing.     */
2293 /*                                                                  */
2294 /*------------------------------------------------------------------*/
2295
2296 static void
2297 print_ins (int i, MonoInst *ins)
2298 {
2299         const char *spec = ins_spec [ins->opcode];
2300         g_print ("\t%-2d %s", i, mono_inst_name (ins->opcode));
2301         if (spec [MONO_INST_DEST]) {
2302                 if (ins->dreg >= MONO_MAX_IREGS)
2303                         g_print (" R%d <-", ins->dreg);
2304                 else
2305                         g_print (" %s <-", mono_arch_regname (ins->dreg));
2306         }
2307         if (spec [MONO_INST_SRC1]) {
2308                 if (ins->sreg1 >= MONO_MAX_IREGS)
2309                         g_print (" R%d", ins->sreg1);
2310                 else
2311                         g_print (" %s", mono_arch_regname (ins->sreg1));
2312         }
2313         if (spec [MONO_INST_SRC2]) {
2314                 if (ins->sreg2 >= MONO_MAX_IREGS)
2315                         g_print (" R%d", ins->sreg2);
2316                 else
2317                         g_print (" %s", mono_arch_regname (ins->sreg2));
2318         }
2319         if (spec [MONO_INST_CLOB])
2320                 g_print (" clobbers: %c", spec [MONO_INST_CLOB]);
2321         g_print ("\n");
2322 }
2323
2324 /*========================= End of Function ========================*/
2325
2326 /*------------------------------------------------------------------*/
2327 /*                                                                  */
2328 /* Name         - print_regtrack.                                   */
2329 /*                                                                  */
2330 /* Function     -                                                   */
2331 /*                                                                  */
2332 /*------------------------------------------------------------------*/
2333
2334 static void
2335 print_regtrack (RegTrack *t, int num)
2336 {
2337         int i;
2338         char buf [32];
2339         const char *r;
2340         
2341         for (i = 0; i < num; ++i) {
2342                 if (!t [i].born_in)
2343                         continue;
2344                 if (i >= MONO_MAX_IREGS) {
2345                         g_snprintf (buf, sizeof(buf), "R%d", i);
2346                         r = buf;
2347                 } else
2348                         r = mono_arch_regname (i);
2349                 g_print ("liveness: %s [%d - %d]\n", r, t [i].born_in, t[i].last_use);
2350         }
2351 }
2352
2353 /*========================= End of Function ========================*/
2354
2355 /*------------------------------------------------------------------*/
2356 /*                                                                  */
2357 /* Name         - inst_list_prepend                                 */
2358 /*                                                                  */
2359 /* Function     - Prepend an instruction to the list.               */
2360 /*                                                                  */
2361 /*------------------------------------------------------------------*/
2362
2363 static inline InstList*
2364 inst_list_prepend (MonoMemPool *pool, InstList *list, MonoInst *data)
2365 {
2366         InstList *item = mono_mempool_alloc (pool, sizeof (InstList));
2367         item->data = data;
2368         item->prev = NULL;
2369         item->next = list;
2370         if (list)
2371                 list->prev = item;
2372         return item;
2373 }
2374
2375 /*========================= End of Function ========================*/
2376
2377 /*------------------------------------------------------------------*/
2378 /*                                                                  */
2379 /* Name         - get_register_force_spilling                       */
2380 /*                                                                  */
2381 /* Function     - Force the spilling of the variable in the         */
2382 /*                symbolic register 'reg'.                          */
2383 /*                                                                  */
2384 /*------------------------------------------------------------------*/
2385
2386 static int
2387 get_register_force_spilling (MonoCompile *cfg, InstList *item, MonoInst *ins, int reg)
2388 {
2389         MonoInst *load;
2390         int i, sel, spill;
2391         
2392         sel = cfg->rs->iassign [reg];
2393         i = reg;
2394         spill = ++cfg->spill_count;
2395         cfg->rs->iassign [i] = -spill - 1;
2396         mono_regstate_free_int (cfg->rs, sel);
2397         /*----------------------------------------------------------*/
2398         /* we need to create a spill var and insert a load to sel   */
2399         /* after the current instruction                            */
2400         /*----------------------------------------------------------*/
2401         MONO_INST_NEW (cfg, load, OP_LOAD_MEMBASE);
2402         load->dreg = sel;
2403         load->inst_basereg = cfg->frame_reg;
2404         load->inst_offset = mono_spillvar_offset (cfg, spill);
2405         if (item->prev) {
2406                 while (ins->next != item->prev->data)
2407                         ins = ins->next;
2408         }
2409         load->next = ins->next;
2410         ins->next  = load;
2411         DEBUG (g_print ("SPILLED LOAD (%d at 0x%08x(%%sp)) R%d (freed %s)\n", 
2412                         spill, load->inst_offset, i, mono_arch_regname (sel)));
2413         i = mono_regstate_alloc_int (cfg->rs, 1 << sel);
2414         g_assert (i == sel);
2415
2416         return sel;
2417 }
2418
2419 /*========================= End of Function ========================*/
2420
2421 /*------------------------------------------------------------------*/
2422 /*                                                                  */
2423 /* Name         -  get_register_spilling                            */
2424 /*                                                                  */
2425 /* Function     -                                                   */
2426 /*                                                                  */
2427 /*------------------------------------------------------------------*/
2428
2429 static int
2430 get_register_spilling (MonoCompile *cfg, InstList *item, MonoInst *ins, guint32 regmask, int reg)
2431 {
2432         MonoInst *load;
2433         int i, sel, spill;
2434
2435         DEBUG (g_print ("start regmask to assign R%d: 0x%08x (R%d <- R%d R%d)\n", reg, regmask, ins->dreg, ins->sreg1, ins->sreg2));
2436         /* exclude the registers in the current instruction */
2437         if (reg != ins->sreg1 && 
2438             (reg_is_freeable (ins->sreg1) || 
2439              (ins->sreg1 >= MONO_MAX_IREGS && 
2440               cfg->rs->iassign [ins->sreg1] >= 0))) {
2441                 if (ins->sreg1 >= MONO_MAX_IREGS)
2442                         regmask &= ~ (1 << cfg->rs->iassign [ins->sreg1]);
2443                 else
2444                         regmask &= ~ (1 << ins->sreg1);
2445                 DEBUG (g_print ("excluding sreg1 %s\n", mono_arch_regname (ins->sreg1)));
2446         }
2447         if (reg != ins->sreg2 && 
2448             (reg_is_freeable (ins->sreg2) || 
2449              (ins->sreg2 >= MONO_MAX_IREGS && 
2450               cfg->rs->iassign [ins->sreg2] >= 0))) {
2451                 if (ins->sreg2 >= MONO_MAX_IREGS)
2452                         regmask &= ~ (1 << cfg->rs->iassign [ins->sreg2]);
2453                 else
2454                         regmask &= ~ (1 << ins->sreg2);
2455                 DEBUG (g_print ("excluding sreg2 %s %d\n", mono_arch_regname (ins->sreg2), ins->sreg2));
2456         }
2457         if (reg != ins->dreg && reg_is_freeable (ins->dreg)) {
2458                 regmask &= ~ (1 << ins->dreg);
2459                 DEBUG (g_print ("excluding dreg %s\n", mono_arch_regname (ins->dreg)));
2460         }
2461
2462         DEBUG (g_print ("available regmask: 0x%08x\n", regmask));
2463         g_assert (regmask); /* need at least a register we can free */
2464         sel = -1;
2465         /* we should track prev_use and spill the register that's farther */
2466         for (i = 0; i < MONO_MAX_IREGS; ++i) {
2467                 if (regmask & (1 << i)) {
2468                         sel = i;
2469                         DEBUG (g_print ("selected register %s has assignment %d\n", mono_arch_regname (sel), cfg->rs->iassign [sel]));
2470                         break;
2471                 }
2472         }
2473         i = cfg->rs->isymbolic [sel];
2474         spill = ++cfg->spill_count;
2475         cfg->rs->iassign [i] = -spill - 1;
2476         mono_regstate_free_int (cfg->rs, sel);
2477         /* we need to create a spill var and insert a load to sel after the current instruction */
2478         MONO_INST_NEW (cfg, load, OP_LOAD_MEMBASE);
2479         load->dreg = sel;
2480         load->inst_basereg = cfg->frame_reg;
2481         load->inst_offset = mono_spillvar_offset (cfg, spill);
2482         if (item->prev) {
2483                 while (ins->next != item->prev->data)
2484                         ins = ins->next;
2485         }
2486         load->next = ins->next;
2487         ins->next = load;
2488         DEBUG (g_print ("SPILLED LOAD (%d at 0x%08x(%%sp)) R%d (freed %s)\n", spill, load->inst_offset, i, mono_arch_regname (sel)));
2489         i = mono_regstate_alloc_int (cfg->rs, 1 << sel);
2490         g_assert (i == sel);
2491         
2492         return sel;
2493 }
2494
2495 /*========================= End of Function ========================*/
2496
2497 /*------------------------------------------------------------------*/
2498 /*                                                                  */
2499 /* Name         - get_float_register_spilling                       */
2500 /*                                                                  */
2501 /* Function     -                                                   */
2502 /*                                                                  */
2503 /*------------------------------------------------------------------*/
2504
2505 static int
2506 get_float_register_spilling (MonoCompile *cfg, InstList *item, MonoInst *ins, guint32 regmask, int reg)
2507 {
2508         MonoInst *load;
2509         int i, sel, spill;
2510
2511         DEBUG (g_print ("start regmask to assign R%d: 0x%08x (R%d <- R%d R%d)\n", reg, regmask, ins->dreg, ins->sreg1, ins->sreg2));
2512         /* exclude the registers in the current instruction */
2513         if (reg != ins->sreg1 && 
2514             (freg_is_freeable (ins->sreg1) || 
2515              (ins->sreg1 >= MONO_MAX_FREGS && 
2516               cfg->rs->fassign [ins->sreg1] >= 0))) {
2517                 if (ins->sreg1 >= MONO_MAX_FREGS)
2518                         regmask &= ~ (1 << cfg->rs->fassign [ins->sreg1]);
2519                 else
2520                         regmask &= ~ (1 << ins->sreg1);
2521                 DEBUG (g_print ("excluding sreg1 %s\n", mono_arch_regname (ins->sreg1)));
2522         }
2523         if (reg != ins->sreg2 && 
2524             (freg_is_freeable (ins->sreg2) || 
2525              (ins->sreg2 >= MONO_MAX_FREGS &&
2526               cfg->rs->fassign [ins->sreg2] >= 0))) {
2527                 if (ins->sreg2 >= MONO_MAX_FREGS)
2528                         regmask &= ~ (1 << cfg->rs->fassign [ins->sreg2]);
2529                 else
2530                         regmask &= ~ (1 << ins->sreg2);
2531                 DEBUG (g_print ("excluding sreg2 %s %d\n", mono_arch_regname (ins->sreg2), ins->sreg2));
2532         }
2533         if (reg != ins->dreg && freg_is_freeable (ins->dreg)) {
2534                 regmask &= ~ (1 << ins->dreg);
2535                 DEBUG (g_print ("excluding dreg %s\n", mono_arch_regname (ins->dreg)));
2536         }
2537
2538         DEBUG (g_print ("available regmask: 0x%08x\n", regmask));
2539         g_assert (regmask); /* need at least a register we can free */
2540         sel = -1;
2541         /* we should track prev_use and spill the register that's farther */
2542         for (i = 0; i < MONO_MAX_FREGS; ++i) {
2543                 if (regmask & (1 << i)) {
2544                         sel = i;
2545                         DEBUG (g_print ("selected register %s has assignment %d\n", 
2546                                         mono_arch_regname (sel), cfg->rs->fassign [sel]));
2547                         break;
2548                 }
2549         }
2550         i = cfg->rs->fsymbolic [sel];
2551         spill = ++cfg->spill_count;
2552         cfg->rs->fassign [i] = -spill - 1;
2553         mono_regstate_free_float(cfg->rs, sel);
2554         /* we need to create a spill var and insert a load to sel after the current instruction */
2555         MONO_INST_NEW (cfg, load, OP_LOADR8_MEMBASE);
2556         load->dreg = sel;
2557         load->inst_basereg = cfg->frame_reg;
2558         load->inst_offset = mono_spillvar_offset_float (cfg, spill);
2559         if (item->prev) {
2560                 while (ins->next != item->prev->data)
2561                         ins = ins->next;
2562         }
2563         load->next = ins->next;
2564         ins->next = load;
2565         DEBUG (g_print ("SPILLED LOAD (%d at 0x%08x(%%sp)) R%d (freed %s)\n", spill, load->inst_offset, i, mono_arch_regname (sel)));
2566         i = mono_regstate_alloc_float (cfg->rs, 1 << sel);
2567         g_assert (i == sel);
2568         
2569         return sel;
2570 }
2571
2572 /*========================= End of Function ========================*/
2573
2574 /*------------------------------------------------------------------*/
2575 /*                                                                  */
2576 /* Name         - create_copy_ins                                   */
2577 /*                                                                  */
2578 /* Function     - Create an instruction to copy from reg to reg.    */
2579 /*                                                                  */
2580 /*------------------------------------------------------------------*/
2581
2582 static MonoInst*
2583 create_copy_ins (MonoCompile *cfg, int dest, int src, MonoInst *ins)
2584 {
2585         MonoInst *copy;
2586         MONO_INST_NEW (cfg, copy, OP_MOVE);
2587         copy->dreg = dest;
2588         copy->sreg1 = src;
2589         if (ins) {
2590                 copy->next = ins->next;
2591                 ins->next = copy;
2592         }
2593         DEBUG (g_print ("\tforced copy from %s to %s\n", 
2594                         mono_arch_regname (src), mono_arch_regname (dest)));
2595         return copy;
2596 }
2597
2598 /*========================= End of Function ========================*/
2599
2600 /*------------------------------------------------------------------*/
2601 /*                                                                  */
2602 /* Name         - create_copy_ins_float                             */
2603 /*                                                                  */
2604 /* Function     - Create an instruction to copy from float reg to   */
2605 /*                float reg.                                        */
2606 /*                                                                  */
2607 /*------------------------------------------------------------------*/
2608
2609 static MonoInst*
2610 create_copy_ins_float (MonoCompile *cfg, int dest, int src, MonoInst *ins)
2611 {
2612         MonoInst *copy;
2613         MONO_INST_NEW (cfg, copy, OP_FMOVE);
2614         copy->dreg = dest;
2615         copy->sreg1 = src;
2616         if (ins) {
2617                 copy->next = ins->next;
2618                 ins->next = copy;
2619         }
2620         DEBUG (g_print ("\tforced copy from %s to %s\n", 
2621                         mono_arch_regname (src), mono_arch_regname (dest)));
2622         return copy;
2623 }
2624
2625 /*========================= End of Function ========================*/
2626
2627 /*------------------------------------------------------------------*/
2628 /*                                                                  */
2629 /* Name         - create_spilled_store                              */
2630 /*                                                                  */
2631 /* Function     - Spill register to storage.                        */
2632 /*                                                                  */
2633 /*------------------------------------------------------------------*/
2634
2635 static MonoInst*
2636 create_spilled_store (MonoCompile *cfg, int spill, int reg, int prev_reg, MonoInst *ins)
2637 {
2638         MonoInst *store;
2639         MONO_INST_NEW (cfg, store, OP_STORE_MEMBASE_REG);
2640         store->sreg1 = reg;
2641         store->inst_destbasereg = cfg->frame_reg;
2642         store->inst_offset = mono_spillvar_offset (cfg, spill);
2643         if (ins) {
2644                 store->next = ins->next;
2645                 ins->next = store;
2646         }
2647         DEBUG (g_print ("SPILLED STORE (%d at 0x%08x(%%sp)) R%d (from %s)\n", 
2648                         spill, store->inst_offset, prev_reg, mono_arch_regname (reg)));
2649         return store;
2650 }
2651
2652 /*========================= End of Function ========================*/
2653
2654 /*------------------------------------------------------------------*/
2655 /*                                                                  */
2656 /* Name         - create_spilled_store_float                        */
2657 /*                                                                  */
2658 /* Function     - Spill floating point register to storage.         */
2659 /*                                                                  */
2660 /*------------------------------------------------------------------*/
2661
2662 static MonoInst*
2663 create_spilled_store_float (MonoCompile *cfg, int spill, int reg, int prev_reg, MonoInst *ins)
2664 {
2665         MonoInst *store;
2666         MONO_INST_NEW (cfg, store, OP_STORER8_MEMBASE_REG);
2667         store->sreg1 = reg;
2668         store->inst_destbasereg = cfg->frame_reg;
2669         store->inst_offset = mono_spillvar_offset_float (cfg, spill);
2670         if (ins) {
2671                 store->next = ins->next;
2672                 ins->next = store;
2673         }
2674         DEBUG (g_print ("SPILLED STORE (%d at 0x%08x(%%sp)) R%d (from %s)\n", 
2675                         spill, store->inst_offset, prev_reg, mono_arch_regname (reg)));
2676         return store;
2677 }
2678
2679 /*========================= End of Function ========================*/
2680
2681 /*------------------------------------------------------------------*/
2682 /*                                                                  */
2683 /* Name         - insert_before_ins                                 */
2684 /*                                                                  */
2685 /* Function     - Insert an instruction before another.             */
2686 /*                                                                  */
2687 /*------------------------------------------------------------------*/
2688
2689 static void
2690 insert_before_ins (MonoInst *ins, InstList *item, MonoInst* to_insert)
2691 {
2692         MonoInst *prev;
2693         g_assert (item->next);
2694         prev = item->next->data;
2695
2696         while (prev->next != ins)
2697                 prev = prev->next;
2698         to_insert->next = ins;
2699         prev->next = to_insert;
2700         /* 
2701          * needed otherwise in the next instruction we can add an ins to the 
2702          * end and that would get past this instruction.
2703          */
2704         item->data = to_insert; 
2705 }
2706
2707 /*========================= End of Function ========================*/
2708
2709 /*------------------------------------------------------------------*/
2710 /*                                                                  */
2711 /* Name         - alloc_int_reg                                     */
2712 /*                                                                  */
2713 /* Function     - Allocate a general register.                      */
2714 /*                                                                  */
2715 /*------------------------------------------------------------------*/
2716
2717 static int
2718 alloc_int_reg (MonoCompile *cfg, InstList *curinst, MonoInst *ins, int sym_reg, guint32 allow_mask)
2719 {
2720         int val = cfg->rs->iassign [sym_reg];
2721         DEBUG (g_print ("Allocating a general register for %d (%d) with mask %08x\n",val,sym_reg,allow_mask));
2722         if (val < 0) {
2723                 int spill = 0;
2724                 if (val < -1) {
2725                         /* the register gets spilled after this inst */
2726                         spill = -val -1;
2727                 }
2728                 val = mono_regstate_alloc_int (cfg->rs, allow_mask);
2729                 if (val < 0)
2730                         val = get_register_spilling (cfg, curinst, ins, allow_mask, sym_reg);
2731                 cfg->rs->iassign [sym_reg] = val;
2732                 /* add option to store before the instruction for src registers */
2733                 if (spill)
2734                         create_spilled_store (cfg, spill, val, sym_reg, ins);
2735         }
2736         DEBUG (g_print ("Allocated %d for %d\n",val,sym_reg));
2737         cfg->rs->isymbolic [val] = sym_reg;
2738         return val;
2739 }
2740
2741 /*========================= End of Function ========================*/
2742
2743 /*------------------------------------------------------------------*/
2744 /*                                                                  */
2745 /* Name         - mono_arch_local_regalloc.                         */
2746 /*                                                                  */
2747 /* Function     - We first scan the list of instructions and we     */
2748 /*                save the liveness information of each register    */
2749 /*                (when the register is first used, when its value  */
2750 /*                is set etc.). We also reverse the list of instr-  */
2751 /*                uctions (in the InstList list) because assigning  */
2752 /*                registers backwards allows for more tricks to be  */
2753 /*                used.                                             */
2754 /*                                                                  */
2755 /*------------------------------------------------------------------*/
2756
2757 void
2758 mono_arch_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
2759 {
2760         MonoInst *ins;
2761         MonoRegState *rs = cfg->rs;
2762         int i, val;
2763         RegTrack *reginfo, *reginfof;
2764         RegTrack *reginfo1, *reginfo2, *reginfod;
2765         InstList *tmp, *reversed = NULL;
2766         const char *spec;
2767         guint32 src1_mask, src2_mask, dest_mask;
2768         guint32 cur_iregs, cur_fregs;
2769
2770         if (!bb->code)
2771                 return;
2772         rs->next_vireg = bb->max_ireg;
2773         rs->next_vfreg = bb->max_freg;
2774         mono_regstate_assign (rs);
2775         reginfo = mono_mempool_alloc0 (cfg->mempool, sizeof (RegTrack) * rs->next_vireg);
2776         reginfof = mono_mempool_alloc0 (cfg->mempool, sizeof (RegTrack) * rs->next_vfreg);
2777         rs->ifree_mask = S390_CALLER_REGS;
2778         rs->ffree_mask = S390_CALLER_FREGS;
2779
2780         ins = bb->code;
2781         i = 1;
2782         DEBUG (g_print ("LOCAL regalloc: basic block: %d\n", bb->block_num));
2783         /* forward pass on the instructions to collect register liveness info */
2784         while (ins) {
2785                 spec = ins_spec [ins->opcode];
2786                 DEBUG (print_ins (i, ins));
2787 //              if (spec [MONO_INST_CLOB] == 'c') {
2788 //                      MonoCallInst * call = (MonoCallInst*)ins;
2789 //                      int j;
2790 //              }
2791                 if (spec [MONO_INST_SRC1]) {
2792                         if (spec [MONO_INST_SRC1] == 'f')
2793                                 reginfo1 = reginfof;
2794                         else
2795                                 reginfo1 = reginfo;
2796                         reginfo1 [ins->sreg1].prev_use = reginfo1 [ins->sreg1].last_use;
2797                         reginfo1 [ins->sreg1].last_use = i;
2798                 } else {
2799                         ins->sreg1 = -1;
2800                 }
2801                 if (spec [MONO_INST_SRC2]) {
2802                         if (spec [MONO_INST_SRC2] == 'f')
2803                                 reginfo2 = reginfof;
2804                         else
2805                                 reginfo2 = reginfo;
2806                         reginfo2 [ins->sreg2].prev_use = reginfo2 [ins->sreg2].last_use;
2807                         reginfo2 [ins->sreg2].last_use = i;
2808                 } else {
2809                         ins->sreg2 = -1;
2810                 }
2811                 if (spec [MONO_INST_DEST]) {
2812                         if (spec [MONO_INST_DEST] == 'f')
2813                                 reginfod = reginfof;
2814                         else
2815                                 reginfod = reginfo;
2816                         if (spec [MONO_INST_DEST] != 'b') /* it's not just a base register */
2817                                 reginfod [ins->dreg].killed_in = i;
2818                         reginfod [ins->dreg].prev_use = reginfod [ins->dreg].last_use;
2819                         reginfod [ins->dreg].last_use = i;
2820                         if (reginfod [ins->dreg].born_in == 0 || reginfod [ins->dreg].born_in > i)
2821                                 reginfod [ins->dreg].born_in = i;
2822                         if (spec [MONO_INST_DEST] == 'l') {
2823                                 /* result in R2/R3, the virtual register is allocated sequentially */
2824                                 reginfod [ins->dreg + 1].prev_use = reginfod [ins->dreg + 1].last_use;
2825                                 reginfod [ins->dreg + 1].last_use = i;
2826                                 if (reginfod [ins->dreg + 1].born_in == 0 || reginfod [ins->dreg + 1].born_in > i)
2827                                         reginfod [ins->dreg + 1].born_in = i;
2828                         }
2829                 } else {
2830                         ins->dreg = -1;
2831                 }
2832                 reversed = inst_list_prepend (cfg->mempool, reversed, ins);
2833                 ++i;
2834                 ins = ins->next;
2835         }
2836
2837         cur_iregs = S390_CALLER_REGS;
2838         cur_fregs = S390_CALLER_FREGS;
2839
2840         DEBUG (print_regtrack (reginfo, rs->next_vireg));
2841         DEBUG (print_regtrack (reginfof, rs->next_vfreg));
2842         tmp = reversed;
2843         while (tmp) {
2844                 int prev_dreg, prev_sreg1, prev_sreg2;
2845                 --i;
2846                 ins = tmp->data;
2847                 spec = ins_spec [ins->opcode];
2848                 DEBUG (g_print ("processing:"));
2849                 DEBUG (print_ins (i, ins));
2850                 /* make the register available for allocation: FIXME add fp reg */
2851                 if (ins->opcode == OP_SETREG || ins->opcode == OP_SETREGIMM) {
2852                         cur_iregs |= 1 << ins->dreg;
2853                         DEBUG (g_print ("adding %d to cur_iregs\n", ins->dreg));
2854                 } else if (ins->opcode == OP_SETFREG) {
2855                         cur_fregs |= 1 << ins->dreg;
2856                         DEBUG (g_print ("adding %d to cur_fregs\n", ins->dreg));
2857                 } else if (spec [MONO_INST_CLOB] == 'c') {
2858                         MonoCallInst *cinst = (MonoCallInst*)ins;
2859                         DEBUG (g_print ("excluding regs 0x%x from cur_iregs (0x%x)\n", 
2860                                         cinst->used_iregs, cur_iregs));
2861                         DEBUG (g_print ("excluding fpregs 0x%x from cur_fregs (0x%x)\n", 
2862                                         cinst->used_fregs, cur_fregs));
2863                         cur_iregs &= ~cinst->used_iregs;
2864                         cur_fregs &= ~cinst->used_fregs;
2865                         DEBUG (g_print ("available cur_iregs: 0x%x\n", cur_iregs));
2866                         DEBUG (g_print ("available cur_fregs: 0x%x\n", cur_fregs));
2867                         /*------------------------------------------------------------*/
2868                         /* registers used by the calling convention are excluded from */ 
2869                         /* allocation: they will be selectively enabled when they are */ 
2870                         /* assigned by the special SETREG opcodes.                    */
2871                         /*------------------------------------------------------------*/
2872                 }
2873                 dest_mask = src1_mask = src2_mask = cur_iregs;
2874                 /*------------------------------------------------------*/
2875                 /* update for use with FP regs...                       */
2876                 /*------------------------------------------------------*/
2877                 if (spec [MONO_INST_DEST] == 'f') {
2878                         dest_mask = cur_fregs;
2879                         if (ins->dreg >= MONO_MAX_FREGS) {
2880                                 val = rs->fassign [ins->dreg];
2881                                 prev_dreg = ins->dreg;
2882                                 if (val < 0) {
2883                                         int spill = 0;
2884                                         if (val < -1) {
2885                                                 /* the register gets spilled after this inst */
2886                                                 spill = -val -1;
2887                                         }
2888                                         val = mono_regstate_alloc_float (rs, dest_mask);
2889                                         if (val < 0)
2890                                                 val = get_float_register_spilling (cfg, tmp, ins, dest_mask, ins->dreg);
2891                                         rs->fassign [ins->dreg] = val;
2892                                         if (spill)
2893                                                 create_spilled_store_float (cfg, spill, val, prev_dreg, ins);
2894                                 }
2895                                 DEBUG (g_print ("\tassigned dreg %s to dest R%d\n", 
2896                                                 mono_arch_regname (val), ins->dreg));
2897                                 rs->fsymbolic [val] = prev_dreg;
2898                                 ins->dreg = val;
2899                                 if (spec [MONO_INST_CLOB] == 'c' && ins->dreg != s390_f0) {
2900                                         /* this instruction only outputs to s390_f0, need to copy */
2901                                         create_copy_ins_float (cfg, ins->dreg, s390_f0, ins);
2902                                 }
2903                         } else {
2904                                 prev_dreg = -1;
2905                         }
2906                         if (freg_is_freeable (ins->dreg) && prev_dreg >= 0 && (reginfof [prev_dreg].born_in >= i || !(cur_fregs & (1 << ins->dreg)))) {
2907                                 DEBUG (g_print ("\tfreeable %s (R%d) (born in %d)\n", mono_arch_regname (ins->dreg), prev_dreg, reginfo [prev_dreg].born_in));
2908                                 mono_regstate_free_float (rs, ins->dreg);
2909                         }
2910                 } else if (ins->dreg >= MONO_MAX_IREGS) {
2911                         val = rs->iassign [ins->dreg];
2912                         prev_dreg = ins->dreg;
2913                         if (val < 0) {
2914                                 int spill = 0;
2915                                 if (val < -1) {
2916                                         /* the register gets spilled after this inst */
2917                                         spill = -val -1;
2918                                 }
2919                                 val = mono_regstate_alloc_int (rs, dest_mask);
2920                                 if (val < 0)
2921                                         val = get_register_spilling (cfg, tmp, ins, dest_mask, ins->dreg);
2922                                 rs->iassign [ins->dreg] = val;
2923                                 if (spill)
2924                                         create_spilled_store (cfg, spill, val, prev_dreg, ins);
2925                         }
2926                         DEBUG (g_print ("\tassigned dreg %s to dest R%d (prev: R%d)\n", 
2927                                         mono_arch_regname (val), ins->dreg, prev_dreg));
2928                         rs->isymbolic [val] = prev_dreg;
2929                         ins->dreg = val;
2930                         if (spec [MONO_INST_DEST] == 'l') {
2931                                 int hreg = prev_dreg + 1;
2932                                 val = rs->iassign [hreg];
2933                                 if (val < 0) {
2934                                         int spill = 0;
2935                                         if (val < -1) {
2936                                                 /* the register gets spilled after this inst */
2937                                                 spill = -val -1;
2938                                         }
2939                                         val = mono_regstate_alloc_int (rs, dest_mask);
2940                                         if (val < 0)
2941                                                 val = get_register_spilling (cfg, tmp, ins, dest_mask, hreg);
2942                                         rs->iassign [hreg] = val;
2943                                         if (spill)
2944                                                 create_spilled_store (cfg, spill, val, hreg, ins);
2945                                 }
2946                                 DEBUG (g_print ("\tassigned hreg %s to dest R%d\n", mono_arch_regname (val), hreg));
2947                                 rs->isymbolic [val] = hreg;
2948                                 /* FIXME:? ins->dreg = val; */
2949                                 if (ins->dreg == s390_r3) {
2950                                         if (val != s390_r2)
2951                                                 create_copy_ins (cfg, val, s390_r2, ins);
2952                                 } else if (ins->dreg == s390_r2) {
2953                                         if (val == s390_r3) {
2954                                                 /* swap */
2955                                                 create_copy_ins (cfg, s390_r3, s390_r0, ins);
2956                                                 create_copy_ins (cfg, s390_r2, s390_r3, ins);
2957                                                 create_copy_ins (cfg, s390_r0, s390_r2, ins);
2958                                         } else {
2959                                                 /* two forced copies */
2960                                                 create_copy_ins (cfg, ins->dreg, s390_r3, ins);
2961                                                 create_copy_ins (cfg, val, s390_r2, ins);
2962                                         }
2963                                 } else {
2964                                         if (val == s390_r2) {
2965                                                 create_copy_ins (cfg, ins->dreg, s390_r2, ins);
2966                                         } else {
2967                                                 /* two forced copies */
2968                                                 create_copy_ins (cfg, val, s390_r2, ins);
2969                                                 create_copy_ins (cfg, ins->dreg, s390_r3, ins);
2970                                         }
2971                                 }
2972                                 if (reg_is_freeable (val) && 
2973                                     hreg >= 0 && 
2974                                     (reginfo [hreg].born_in >= i && 
2975                                      !(cur_iregs & (1 << val)))) {
2976                                         DEBUG (g_print ("\tfreeable %s (R%d)\n", mono_arch_regname (val), hreg));
2977                                         mono_regstate_free_int (rs, val);
2978                                 }
2979                         } else if (spec [MONO_INST_DEST] == 'a' && ins->dreg != s390_r2 && spec [MONO_INST_CLOB] != 'd') {
2980                                 /* this instruction only outputs to s390_r2, need to copy */
2981                                 create_copy_ins (cfg, ins->dreg, s390_r2, ins);
2982                         }
2983                 } else {
2984                         prev_dreg = -1;
2985                 }
2986                 if (spec [MONO_INST_DEST] == 'f' && 
2987                     freg_is_freeable (ins->dreg) && 
2988                     prev_dreg >= 0 && (reginfof [prev_dreg].born_in >= i)) {
2989                         DEBUG (g_print ("\tfreeable %s (R%d) (born in %d)\n", mono_arch_regname (ins->dreg), prev_dreg, reginfo [prev_dreg].born_in));
2990                         mono_regstate_free_float (rs, ins->dreg);
2991                 } else if (spec [MONO_INST_DEST] != 'f' && 
2992                            reg_is_freeable (ins->dreg) && 
2993                            prev_dreg >= 0 && (reginfo [prev_dreg].born_in >= i)) {
2994                         DEBUG (g_print ("\tfreeable %s (R%d) (born in %d)\n", mono_arch_regname (ins->dreg), prev_dreg, reginfo [prev_dreg].born_in));
2995                          mono_regstate_free_int (rs, ins->dreg);
2996                 }
2997                 if (spec [MONO_INST_SRC1] == 'f') {
2998                         src1_mask = cur_fregs;
2999                         if (ins->sreg1 >= MONO_MAX_FREGS) {
3000                                 val = rs->fassign [ins->sreg1];
3001                                 prev_sreg1 = ins->sreg1;
3002                                 if (val < 0) {
3003                                         int spill = 0;
3004                                         if (val < -1) {
3005                                                 /* the register gets spilled after this inst */
3006                                                 spill = -val -1;
3007                                         }
3008                                         val = mono_regstate_alloc_float (rs, src1_mask);
3009                                         if (val < 0)
3010                                                 val = get_float_register_spilling (cfg, tmp, ins, src1_mask, ins->sreg1);
3011                                         rs->fassign [ins->sreg1] = val;
3012                                         DEBUG (g_print ("\tassigned sreg1 %s to R%d\n", mono_arch_regname (val), ins->sreg1));
3013                                         if (spill) {
3014                                                 MonoInst *store = create_spilled_store_float (cfg, spill, val, prev_sreg1, NULL);
3015                                                 insert_before_ins (ins, tmp, store);
3016                                         }
3017                                 }
3018                                 rs->fsymbolic [val] = prev_sreg1;
3019                                 ins->sreg1 = val;
3020                         } else {
3021                                 prev_sreg1 = -1;
3022                         }
3023                 } else if (ins->sreg1 >= MONO_MAX_IREGS) {
3024                         val = rs->iassign [ins->sreg1];
3025                         prev_sreg1 = ins->sreg1;
3026                         if (val < 0) {
3027                                 int spill = 0;
3028                                 if (val < -1) {
3029                                         /* the register gets spilled after this inst */
3030                                         spill = -val -1;
3031                                 }
3032                                 val = mono_regstate_alloc_int (rs, src1_mask);
3033                                 if (val < 0)
3034                                         val = get_register_spilling (cfg, tmp, ins, 
3035                                                                      src1_mask, 
3036                                                                      ins->sreg1);
3037                                 rs->iassign [ins->sreg1] = val;
3038                                 DEBUG (g_print ("\tassigned sreg1 %s to R%d\n", 
3039                                                 mono_arch_regname (val), ins->sreg1));
3040                                 if (spill) {
3041                                         MonoInst *store; 
3042                                         store = create_spilled_store (cfg, spill, val, 
3043                                                                       prev_sreg1, NULL);
3044                                         insert_before_ins (ins, tmp, store);
3045                                 }
3046                         }
3047                         rs->isymbolic [val] = prev_sreg1;
3048                         ins->sreg1 = val;
3049                 } else {
3050                         prev_sreg1 = -1;
3051                 }
3052                 /*----------------------------------------------*/
3053                 /* handle clobbering of sreg1                   */
3054                 /*----------------------------------------------*/
3055                 if ((spec [MONO_INST_CLOB] == '1' || 
3056                      spec [MONO_INST_CLOB] == 's') && 
3057                     ins->dreg != ins->sreg1) {
3058                         MonoInst *copy; 
3059                         copy = create_copy_ins (cfg, ins->dreg, ins->sreg1, NULL);
3060                         DEBUG (g_print ("\tneed to copy sreg1 %s to dreg %s\n", 
3061                                         mono_arch_regname (ins->sreg1), 
3062                                         mono_arch_regname (ins->dreg)));
3063                         if (ins->sreg2 == -1 || spec [MONO_INST_CLOB] == 's') {
3064                                 /* note: the copy is inserted before the current instruction! */
3065                                 insert_before_ins (ins, tmp, copy);
3066                                 /* we set sreg1 to dest as well */
3067                                 prev_sreg1 = ins->sreg1 = ins->dreg;
3068                         } else {
3069                                 /* inserted after the operation */
3070                                 copy->next = ins->next;
3071                                 ins->next  = copy;
3072                         }
3073                 }
3074
3075                 if (spec [MONO_INST_SRC2] == 'f') {
3076                         src2_mask = cur_fregs;
3077                         if (ins->sreg2 >= MONO_MAX_FREGS) {
3078                                 val = rs->fassign [ins->sreg2];
3079                                 prev_sreg2 = ins->sreg2;
3080                                 if (val < 0) {
3081                                         int spill = 0;
3082                                         if (val < -1) {
3083                                                 /* the register gets spilled after this inst */
3084                                                 spill = -val -1;
3085                                         }
3086                                         val = mono_regstate_alloc_float (rs, src2_mask);
3087                                         if (val < 0)
3088                                                 val = get_float_register_spilling (cfg, tmp, ins, src2_mask, ins->sreg2);
3089                                         rs->fassign [ins->sreg2] = val;
3090                                         DEBUG (g_print ("\tassigned sreg2 %s to R%d\n", mono_arch_regname (val), ins->sreg2));
3091                                         if (spill)
3092                                                 create_spilled_store_float (cfg, spill, val, prev_sreg2, ins);
3093                                 }
3094                                 rs->fsymbolic [val] = prev_sreg2;
3095                                 ins->sreg2 = val;
3096                         } else {
3097                                 prev_sreg2 = -1;
3098                         }
3099                 } else if (ins->sreg2 >= MONO_MAX_IREGS) {
3100                         val = rs->iassign [ins->sreg2];
3101                         prev_sreg2 = ins->sreg2;
3102                         if (val < 0) {
3103                                 int spill = 0;
3104                                 if (val < -1) {
3105                                         /* the register gets spilled after this inst */
3106                                         spill = -val -1;
3107                                 }
3108                                 val = mono_regstate_alloc_int (rs, src2_mask);
3109                                 if (val < 0)
3110                                         val = get_register_spilling (cfg, tmp, ins, src2_mask, ins->sreg2);
3111                                 rs->iassign [ins->sreg2] = val;
3112                                 DEBUG (g_print ("\tassigned sreg2 %s to R%d\n", mono_arch_regname (val), ins->sreg2));
3113                                 if (spill)
3114                                         create_spilled_store (cfg, spill, val, prev_sreg2, ins);
3115                         }
3116                         rs->isymbolic [val] = prev_sreg2;
3117                         ins->sreg2 = val;
3118                 } else {
3119                         prev_sreg2 = -1;
3120                 }
3121
3122                 if (spec [MONO_INST_CLOB] == 'c') {
3123                         int j, s;
3124                         guint32 clob_mask = S390_CALLER_REGS;
3125                         for (j = 0; j < MONO_MAX_IREGS; ++j) {
3126                                 s = 1 << j;
3127                                 if ((clob_mask & s) && !(rs->ifree_mask & s) && j != ins->sreg1) {
3128                                         //g_warning ("register %s busy at call site\n", mono_arch_regname (j));
3129                                 }
3130                         }
3131                 }
3132                 tmp = tmp->next;
3133         }
3134 }
3135
3136 /*========================= End of Function ========================*/
3137
3138 /*------------------------------------------------------------------*/
3139 /*                                                                  */
3140 /* Name         - emit_float_to_int                                 */
3141 /*                                                                  */
3142 /* Function     - Create instructions which will convert a floating */
3143 /*                point value to integer.                           */
3144 /*                                                                  */
3145 /*------------------------------------------------------------------*/
3146
3147 static guchar*
3148 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
3149 {
3150         /* sreg is a float, dreg is an integer reg. */
3151         if (is_signed) {
3152                 s390_cfdbr (code, dreg, 5, sreg);
3153                 switch (size) {
3154                         case 1:
3155                                 s390_lhi  (code, s390_r0, 0);
3156                                 s390_lhi  (code, s390_r13, 0xff);
3157                                 s390_ltr  (code, dreg, dreg);
3158                                 s390_jnl  (code, 4);
3159                                 s390_lhi  (code, s390_r0, 0x80);
3160                                 s390_nr   (code, dreg, s390_r13);
3161                                 s390_or   (code, dreg, s390_r0);
3162                                 break;
3163                 }
3164         } else {
3165                 s390_basr   (code, s390_r13, 0);
3166                 s390_j      (code, 10);
3167                 s390_llong  (code, 0x41e0000000000000);
3168                 s390_llong  (code, 0x41f0000000000000);
3169                 s390_ldr    (code, s390_f15, sreg);
3170                 s390_cdb    (code, s390_f15, 0, s390_r13, 0);
3171                 s390_jl     (code, 10);
3172                 s390_sdb    (code, s390_f15, 0, s390_r13, 8);
3173                 s390_cfdbr  (code, dreg, 7, s390_f15);
3174                 s390_j      (code, 4);
3175                 s390_cfdbr  (code, dreg, 5, sreg);
3176                 switch (size) {
3177                         case 1: 
3178                                 s390_lhi  (code, s390_r0, 0xff);
3179                                 s390_nr   (code, dreg, s390_r0);
3180                                 break;
3181                         case 2:
3182                                 s390_lhi  (code, s390_r0, -1);
3183                                 s390_srl  (code, s390_r0, 0, 16);
3184                                 s390_nr   (code, dreg, s390_r0);
3185                                 break;
3186                 }
3187         }
3188         return code;
3189 }
3190
3191 /*========================= End of Function ========================*/
3192
3193 /*------------------------------------------------------------------*/
3194 /*                                                                  */
3195 /* Name         - mono_emit_stack_alloc                             */
3196 /*                                                                  */
3197 /* Function     -                                                   */
3198 /*                                                                  */
3199 /*------------------------------------------------------------------*/
3200
3201 static unsigned char*
3202 mono_emit_stack_alloc (guchar *code, MonoInst* tree)
3203 {
3204         return code;
3205 }
3206
3207 /*========================= End of Function ========================*/
3208
3209 /*------------------------------------------------------------------*/
3210 /*                                                                  */
3211 /* Name         - mono_arch_output_basic_block                      */
3212 /*                                                                  */
3213 /* Function     - Perform the "real" work of emitting instructions  */
3214 /*                that will do the work of in the basic block.      */
3215 /*                                                                  */
3216 /*------------------------------------------------------------------*/
3217
3218 void
3219 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3220 {
3221         MonoInst *ins;
3222         MonoCallInst *call;
3223         guint offset;
3224         guint8 *code = cfg->native_code + cfg->code_len;
3225         MonoInst *last_ins = NULL;
3226         guint last_offset = 0;
3227         int max_len, cpos, src2;
3228
3229         if (cfg->opt & MONO_OPT_PEEPHOLE)
3230                 peephole_pass (cfg, bb);
3231
3232         /* we don't align basic blocks of loops on s390 */
3233
3234         if (cfg->verbose_level > 2)
3235                 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3236
3237         cpos = bb->max_offset;
3238
3239         if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
3240                 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
3241                 //g_assert (!mono_compile_aot);
3242                 //cpos += 6;
3243                 //if (bb->cil_code)
3244                 //      cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
3245                 /* this is not thread save, but good enough */
3246                 /* fixme: howto handle overflows? */
3247                 //x86_inc_mem (code, &cov->data [bb->dfn].count); 
3248         }
3249
3250         ins = bb->code;
3251         while (ins) {
3252                 offset = code - cfg->native_code;
3253
3254                 max_len = ((guint8 *)ins_spec [ins->opcode])[MONO_INST_LEN];
3255
3256                 if (offset > (cfg->code_size - max_len - 16)) {
3257                         cfg->code_size *= 2;
3258                         cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3259                         code = cfg->native_code + offset;
3260                 }
3261
3262                 mono_debug_record_line_number (cfg, ins, offset);
3263
3264                 switch (ins->opcode) {
3265                 case OP_STOREI1_MEMBASE_IMM: {
3266                         s390_lhi (code, s390_r0, ins->inst_imm);
3267                         if (s390_is_uimm12(ins->inst_offset))
3268                                 s390_stc (code, s390_r0, 0, ins->inst_destbasereg, ins->inst_offset);
3269                         else {
3270                                 s390_basr (code, s390_r13, 0);
3271                                 s390_j    (code, 4);
3272                                 s390_word (code, ins->inst_offset);
3273                                 s390_l    (code, s390_r13, 0, s390_r13, 4);
3274                                 s390_stc  (code, s390_r0, s390_r13, ins->inst_destbasereg, 0);
3275                         }
3276                 }
3277                         break;
3278                 case OP_STOREI2_MEMBASE_IMM: {
3279                         s390_lhi (code, s390_r0, ins->inst_imm);
3280                         if (s390_is_uimm12(ins->inst_offset)) {
3281                                 s390_sth (code, s390_r0, 0, ins->inst_destbasereg, ins->inst_offset);
3282                         } else {
3283                                 s390_basr (code, s390_r13, 0);
3284                                 s390_j    (code, 4);
3285                                 s390_word (code, ins->inst_offset);
3286                                 s390_l    (code, s390_r13, 0, s390_r13, 4);
3287                                 s390_sth  (code, s390_r0, s390_r13, ins->inst_destbasereg, 0);
3288                         }
3289                 }
3290                         break;
3291                 case OP_STORE_MEMBASE_IMM:
3292                 case OP_STOREI4_MEMBASE_IMM: {
3293                         if (s390_is_uimm16(ins->inst_imm)) {
3294                                 s390_lhi  (code, s390_r0, ins->inst_imm);
3295                         } else {
3296                                 s390_basr (code, s390_r13, 0);
3297                                 s390_j    (code, 4);
3298                                 s390_word (code, ins->inst_imm);
3299                                 s390_l    (code, s390_r0, 0, s390_r13, 4);
3300                         }
3301                         if (s390_is_uimm12(ins->inst_offset)) {
3302                                 s390_st  (code, s390_r0, 0, ins->inst_destbasereg, ins->inst_offset);
3303                         } else {
3304                                 s390_basr (code, s390_r13, 0);
3305                                 s390_j    (code, 4);
3306                                 s390_word (code, ins->inst_offset);
3307                                 s390_l    (code, s390_r13, 0, s390_r13, 4);
3308                                 s390_st   (code, s390_r0, s390_r13, ins->inst_destbasereg, 0);
3309                         }
3310                 }
3311                         break;
3312                 case OP_STOREI1_MEMBASE_REG: {
3313                         if (s390_is_uimm12(ins->inst_offset)) {
3314                                 s390_stc  (code, ins->sreg1, 0, ins->inst_destbasereg, ins->inst_offset);
3315                         } else {
3316                                 s390_basr (code, s390_r13, 0);
3317                                 s390_j    (code, 4);
3318                                 s390_word (code, ins->inst_offset);
3319                                 s390_l    (code, s390_r13, 0, s390_r13, 4);
3320                                 s390_stc  (code, ins->sreg1, s390_r13, ins->inst_destbasereg, 0);
3321                         }
3322                 }
3323                         break;
3324                 case OP_STOREI2_MEMBASE_REG: {
3325                         if (s390_is_uimm12(ins->inst_offset)) {
3326                                 s390_sth  (code, ins->sreg1, 0, ins->inst_destbasereg, ins->inst_offset);
3327                         } else {
3328                                 s390_basr (code, s390_r13, 0);
3329                                 s390_j    (code, 4);
3330                                 s390_word (code, ins->inst_offset);
3331                                 s390_l    (code, s390_r13, 0, s390_r13, 4);
3332                                 s390_sth  (code, ins->sreg1, s390_r13, ins->inst_destbasereg, 0);
3333                         }
3334                 }
3335                         break;
3336                 case OP_STORE_MEMBASE_REG:
3337                 case OP_STOREI4_MEMBASE_REG: {
3338                         if (s390_is_uimm12(ins->inst_offset)) {
3339                                 s390_st   (code, ins->sreg1, 0, ins->inst_destbasereg, ins->inst_offset);
3340                         } else {
3341                                 s390_basr (code, s390_r13, 0);
3342                                 s390_j    (code, 4);
3343                                 s390_word (code, ins->inst_offset);
3344                                 s390_l    (code, s390_r13, 0, s390_r13, 4);
3345                                 s390_st   (code, ins->sreg1, s390_r13, ins->inst_destbasereg, 0);
3346                         }
3347                 }
3348                         break;
3349                 case CEE_LDIND_I:
3350                 case CEE_LDIND_I4:
3351                 case CEE_LDIND_U4: {
3352                         s390_basr (code, s390_r13, 0);
3353                         s390_j    (code, 4);
3354                         s390_word (code, ins->inst_p0);
3355                         s390_l    (code, s390_r13, 0, s390_r13, 4);
3356                         s390_l    (code, ins->dreg, 0, s390_r13, 0);
3357                 }
3358                         break;
3359                 case OP_LOADU4_MEM:
3360                         g_assert_not_reached ();
3361                         break;
3362                 case OP_LOAD_MEMBASE:
3363                 case OP_LOADI4_MEMBASE:
3364                 case OP_LOADU4_MEMBASE: {
3365                         if (s390_is_uimm12(ins->inst_offset))
3366                                 s390_l    (code, ins->dreg, 0, ins->inst_basereg, ins->inst_offset);
3367                         else {
3368                                 if (s390_is_uimm16(ins->inst_offset)) {
3369                                         s390_lhi (code, s390_r13, ins->inst_offset);
3370                                         s390_l   (code, ins->dreg, s390_r13, ins->inst_basereg, 0);
3371                                 } else {
3372                                         s390_basr (code, s390_r13, 0);
3373                                         s390_j    (code, 4);
3374                                         s390_word (code, ins->inst_offset);
3375                                         s390_l    (code, s390_r13, 0, s390_r13, 4);
3376                                         s390_l    (code, ins->dreg, s390_r13, ins->inst_basereg, 0);
3377                                 }
3378                         }
3379                 }
3380                         break;
3381                 case OP_LOADU1_MEMBASE: {
3382                         s390_lhi (code, s390_r0, 0);
3383                         if (s390_is_uimm12(ins->inst_offset))
3384                                 s390_ic   (code, s390_r0, 0, ins->inst_basereg, ins->inst_offset);
3385                         else {
3386                                 s390_basr (code, s390_r13, 0);
3387                                 s390_j    (code, 4);
3388                                 s390_word (code, ins->inst_offset);
3389                                 s390_l    (code, s390_r13, 0, s390_r13, 4);
3390                                 s390_ic   (code, s390_r0, s390_r13, ins->inst_basereg, 0);
3391                         }
3392                         s390_lr   (code, ins->dreg, s390_r0);
3393                 }
3394                         break;
3395                 case OP_LOADI1_MEMBASE: {
3396                         s390_lhi (code, s390_r0, 0);
3397                         if (s390_is_uimm12(ins->inst_offset))
3398                                 s390_ic   (code, s390_r0, 0, ins->inst_basereg, ins->inst_offset);
3399                         else {
3400                                 s390_basr (code, s390_r13, 0);
3401                                 s390_j    (code, 4);
3402                                 s390_word (code, ins->inst_offset);
3403                                 s390_l    (code, s390_r13, 0, s390_r13, 4);
3404                                 s390_ic   (code, s390_r0, s390_r13, ins->inst_basereg, 0);
3405                         }
3406                         s390_lhi  (code, s390_r13, 0x80);
3407                         s390_nr   (code, s390_r13, s390_r0);
3408                         s390_jz   (code, 5);
3409                         s390_lhi  (code, s390_r13, 0xff00);
3410                         s390_or   (code, s390_r0, s390_r13);
3411                         s390_lr   (code, ins->dreg, s390_r0);
3412                 }
3413                         break;
3414                 case OP_LOADU2_MEMBASE: {
3415                         s390_lhi (code, s390_r0, 0);
3416                         if (s390_is_uimm12(ins->inst_offset))
3417                                 s390_icm  (code, s390_r0, 3, ins->inst_basereg, ins->inst_offset);
3418                         else {
3419                                 s390_basr (code, s390_r13, 0);
3420                                 s390_j    (code, 4);
3421                                 s390_word (code, ins->inst_offset);
3422                                 s390_l    (code, s390_r13, 0, s390_r13, 4);
3423                                 s390_ar   (code, s390_r13, ins->inst_basereg);
3424                                 s390_icm  (code, s390_r0, 3, s390_r13, 0);
3425                         }
3426                         s390_lr  (code, ins->dreg, s390_r0);
3427                 }
3428                         break;
3429                 case OP_LOADI2_MEMBASE: {
3430                         s390_lhi (code, s390_r0, 0);
3431                         if (s390_is_uimm12(ins->inst_offset))
3432                                 s390_lh   (code, s390_r0, 0, ins->inst_basereg, ins->inst_offset);
3433                         else {
3434                                 s390_basr (code, s390_r13, 0);
3435                                 s390_j    (code, 4);
3436                                 s390_word (code, ins->inst_offset);
3437                                 s390_l    (code, s390_r13, 0, s390_r13, 4);
3438                                 s390_lh   (code, s390_r0, s390_r13, ins->inst_basereg, 0);
3439                         }
3440                         s390_lr  (code, ins->dreg, s390_r0);
3441                 }
3442                         break;
3443                 case CEE_CONV_I1: {
3444                         s390_lhi  (code, s390_r0, 0x80);
3445                         if (ins->dreg != ins->sreg1) {
3446                                 s390_lr   (code, ins->dreg, ins->sreg1);
3447                         }
3448                         s390_nr   (code, s390_r0, ins->sreg1);
3449                         s390_jz   (code, 7);
3450                         s390_lhi  (code, s390_r13, -1);
3451                         s390_sll  (code, s390_r13, 0, 8);
3452                         s390_or   (code, ins->dreg, s390_r13);
3453                 }
3454                         break;
3455                 case CEE_CONV_I2: {
3456                         s390_lhi  (code, s390_r0, 0x80);
3457                         s390_sll  (code, s390_r0, 0, 8);
3458                         if (ins->dreg != ins->sreg1) {
3459                                 s390_lr   (code, ins->dreg, ins->sreg1);
3460                         }
3461                         s390_nr   (code, s390_r0, ins->sreg1);
3462                         s390_jz   (code, 7);
3463                         s390_lhi  (code, s390_r13, -1);
3464                         s390_sll  (code, s390_r13, 0, 16);
3465                         s390_or   (code, ins->dreg, s390_r13);
3466                 }
3467                         break;
3468                 case CEE_CONV_U1: {
3469                         s390_lhi  (code, s390_r0, 0xff);
3470                         if (ins->dreg != ins->sreg1) {
3471                                 s390_lr   (code, ins->dreg, ins->sreg1);
3472                         }
3473                         s390_nr   (code, ins->dreg, s390_r0);
3474                 }
3475                         break;
3476                 case CEE_CONV_U2: {
3477                         s390_lhi  (code, s390_r0, -1);
3478                         s390_sll  (code, s390_r0, 0, 16);
3479                         s390_srl  (code, s390_r0, 0, 16);
3480                         if (ins->dreg != ins->sreg1) {
3481                                 s390_lr   (code, ins->dreg, ins->sreg1);
3482                         }
3483                         s390_nr   (code, ins->dreg, s390_r0);
3484                 }
3485                         break;
3486                 case OP_COMPARE: {
3487                         if ((ins->next) && 
3488                             ((ins->next->opcode >= CEE_BNE_UN) &&
3489                              (ins->next->opcode <= CEE_BLT_UN)) || 
3490                             ((ins->next->opcode >= OP_COND_EXC_NE_UN) &&
3491                              (ins->next->opcode <= OP_COND_EXC_LT_UN)) ||
3492                             ((ins->next->opcode == OP_CLT_UN) ||
3493                              (ins->next->opcode == OP_CGT_UN)))
3494                                 s390_clr  (code, ins->sreg1, ins->sreg2);
3495                         else
3496                                 s390_cr   (code, ins->sreg1, ins->sreg2);
3497                 }
3498                         break;
3499                 case OP_COMPARE_IMM: {
3500                         if (s390_is_uimm16 (ins->inst_imm)) {
3501                                 s390_lhi  (code, s390_r0, ins->inst_imm);
3502                                 if ((ins->next) && 
3503                                     ((ins->next->opcode >= CEE_BNE_UN) &&
3504                                      (ins->next->opcode <= CEE_BLT_UN)) || 
3505                                     ((ins->next->opcode >= OP_COND_EXC_NE_UN) &&
3506                                      (ins->next->opcode <= OP_COND_EXC_LT_UN)) ||
3507                                     ((ins->next->opcode == OP_CLT_UN) ||
3508                                      (ins->next->opcode == OP_CGT_UN)))
3509                                         s390_clr  (code, ins->sreg1, s390_r0);
3510                                 else
3511                                         s390_cr   (code, ins->sreg1, s390_r0);
3512                         }
3513                         else {
3514                                 s390_basr (code, s390_r13, 0);
3515                                 s390_j    (code, 4);
3516                                 s390_word (code, ins->inst_imm);
3517                                 if ((ins->next) && 
3518                                     ((ins->next->opcode >= CEE_BNE_UN) &&
3519                                      (ins->next->opcode <= CEE_BLT_UN)) || 
3520                                     ((ins->next->opcode >= OP_COND_EXC_NE_UN) &&
3521                                      (ins->next->opcode <= OP_COND_EXC_LT_UN)) ||
3522                                     ((ins->next->opcode == OP_CLT_UN) &&
3523                                      (ins->next->opcode == OP_CGT_UN)))
3524                                         s390_cl   (code, ins->sreg1, 0, s390_r13, 4);
3525                                 else
3526                                         s390_c    (code, ins->sreg1, 0, s390_r13, 4);
3527                         }
3528                 }
3529                         break;
3530                 case OP_X86_TEST_NULL: {
3531                         s390_ltr (code, ins->sreg1, ins->sreg1);
3532                 }
3533                         break;
3534                 case CEE_BREAK: {
3535                         s390_break (code);
3536                 }
3537                         break;
3538                 case OP_ADDCC: {
3539                         CHECK_SRCDST_COM;
3540                         s390_alr  (code, ins->dreg, src2);
3541                 }
3542                         break;
3543                 case CEE_ADD: {
3544                         CHECK_SRCDST_COM;
3545                         s390_ar   (code, ins->dreg, src2);
3546                 }
3547                         break;
3548                 case OP_ADC: {
3549                         CHECK_SRCDST_COM;
3550                         s390_alcr (code, ins->dreg, src2);
3551                 }
3552                         break;
3553                 case OP_ADDCC_IMM:
3554                 case OP_ADD_IMM: {
3555                         if ((ins->next) &&
3556                             (ins->next->opcode == OP_ADC_IMM)) {
3557                                 s390_basr (code, s390_r13, 0);
3558                                 s390_j    (code, 4);
3559                                 s390_word (code, ins->inst_imm);
3560                                 if (ins->dreg != ins->sreg1) {
3561                                         s390_lr   (code, ins->dreg, ins->sreg1);
3562                                 }
3563                                 s390_al   (code, ins->dreg, 0, s390_r13, 4);
3564                         } else {
3565                                 if (s390_is_uimm16 (ins->inst_imm)) {
3566                                         if (ins->dreg != ins->sreg1) {
3567                                                 s390_lr   (code, ins->dreg, ins->sreg1);
3568                                         }
3569                                         s390_ahi (code, ins->dreg, ins->inst_imm);
3570                                 } else {
3571                                         s390_basr (code, s390_r13, 0);
3572                                         s390_j    (code, 4);
3573                                         s390_word (code, ins->inst_imm);
3574                                         if (ins->dreg != ins->sreg1) {
3575                                                 s390_lr   (code, ins->dreg, ins->sreg1);
3576                                         }
3577                                         s390_a    (code, ins->dreg, 0, s390_r13, 4);
3578                                 }
3579                         }
3580                 }
3581                         break;
3582                 case OP_ADC_IMM: {
3583                         if (s390_is_uimm16 (ins->inst_imm)) {
3584                                 if (ins->dreg != ins->sreg1) {
3585                                         s390_lr   (code, ins->dreg, ins->sreg1);
3586                                 } 
3587                                 s390_lhi  (code, s390_r0, ins->inst_imm);
3588                                 s390_alcr (code, ins->dreg, s390_r0);
3589                         } else {
3590                                 s390_basr (code, s390_r13, 0);
3591                                 s390_j    (code, 4);
3592                                 s390_word (code, ins->inst_imm);
3593                                 s390_l    (code, s390_r13, 0, s390_r13, 4);
3594                                 s390_alcr (code, ins->dreg, s390_r13);
3595                         }
3596                 }
3597                         break;
3598                 case CEE_ADD_OVF: {
3599                         CHECK_SRCDST_COM;
3600                         s390_ar   (code, ins->dreg, src2);
3601                         EMIT_COND_SYSTEM_EXCEPTION (S390_CC_OV, "OverflowException");
3602                 }
3603                         break;
3604                 case CEE_ADD_OVF_UN: {
3605                         CHECK_SRCDST_COM;
3606                         s390_alr  (code, ins->dreg, src2);
3607                         EMIT_COND_SYSTEM_EXCEPTION (S390_CC_CY, "OverflowException");
3608                 }
3609                         break;
3610                 case OP_ADD_OVF_CARRY: {
3611                         CHECK_SRCDST_COM;
3612                         s390_lhi  (code, s390_r0, 0);
3613                         s390_lr   (code, s390_r1, s390_r0);
3614                         s390_alcr (code, s390_r0, s390_r1);
3615                         s390_ar   (code, ins->dreg, src2);
3616                         EMIT_COND_SYSTEM_EXCEPTION (S390_CC_OV, "OverflowException");
3617                         s390_ar   (code, ins->dreg, s390_r0);
3618                         EMIT_COND_SYSTEM_EXCEPTION (S390_CC_OV, "OverflowException");
3619                 }
3620                         break;
3621                 case OP_ADD_OVF_UN_CARRY: {
3622                         CHECK_SRCDST_COM;
3623                         s390_alcr (code, ins->dreg, src2);
3624                         EMIT_COND_SYSTEM_EXCEPTION (S390_CC_CY, "OverflowException");
3625                 }
3626                         break;
3627                 case OP_SUBCC: {
3628                         CHECK_SRCDST_NCOM;
3629                         s390_slr (code, ins->dreg, src2);
3630                 }
3631                         break;
3632                 case CEE_SUB: {
3633                         CHECK_SRCDST_NCOM;
3634                         s390_sr   (code, ins->dreg, src2);
3635                 }
3636                         break;
3637                 case OP_SBB: {
3638                         CHECK_SRCDST_NCOM;
3639                         s390_slbr (code, ins->dreg, src2);
3640                 }
3641                         break;
3642                 case OP_SUBCC_IMM: {
3643                         if (s390_is_uimm16 (-ins->inst_imm)) {
3644                                 if (ins->dreg != ins->sreg1) {
3645                                         s390_lr   (code, ins->dreg, ins->sreg1);
3646                                 }
3647                                 s390_ahi  (code, ins->dreg, -ins->inst_imm);
3648                         } else {
3649                                 s390_basr (code, s390_r13, 0);
3650                                 s390_j    (code, 4);
3651                                 s390_word (code, ins->inst_imm);
3652                                 if (ins->dreg != ins->sreg1) {
3653                                         s390_lr   (code, ins->dreg, ins->sreg1);
3654                                 }
3655                                 s390_sl   (code, ins->dreg, 0, s390_r13, 4);
3656                         }
3657                 }
3658                         break;
3659                 case OP_SUB_IMM: {
3660                         if (s390_is_uimm16 (-ins->inst_imm)) {
3661                                 if (ins->dreg != ins->sreg1) {
3662                                         s390_lr   (code, ins->dreg, ins->sreg1);
3663                                 }
3664                                 s390_ahi  (code, ins->dreg, -ins->inst_imm);
3665                         } else {
3666                                 s390_basr (code, s390_r13, 0);
3667                                 s390_j    (code, 4);
3668                                 s390_word (code, ins->inst_imm);
3669                                 if (ins->dreg != ins->sreg1) {
3670                                         s390_lr   (code, ins->dreg, ins->sreg1);
3671                                 }
3672                                 s390_s    (code, ins->dreg, 0, s390_r13, 4);
3673                         }
3674                 }
3675                         break;
3676                 case OP_SBB_IMM: {
3677                         if (ins->dreg != ins->sreg1) {
3678                                 s390_lr    (code, ins->dreg, ins->sreg1);
3679                         }
3680                         if (s390_is_uimm16 (-ins->inst_imm)) {
3681                                 s390_lhi   (code, s390_r0, ins->inst_imm);
3682                                 s390_slbr  (code, ins->dreg, s390_r0);
3683                         } else {
3684                                 s390_basr (code, s390_r13, 0);
3685                                 s390_j    (code, 4);
3686                                 s390_word (code, ins->inst_imm);
3687                                 s390_slb  (code, ins->dreg, 0, s390_r13, 4);
3688                         }
3689                 }
3690                         break;
3691                 case CEE_SUB_OVF: {
3692                         CHECK_SRCDST_NCOM;
3693                         s390_sr   (code, ins->dreg, src2);
3694                         EMIT_COND_SYSTEM_EXCEPTION (S390_CC_OV, "OverflowException");
3695                 }
3696                         break;
3697                 case CEE_SUB_OVF_UN: {
3698                         CHECK_SRCDST_NCOM;
3699                         s390_slr  (code, ins->dreg, src2);
3700                         EMIT_COND_SYSTEM_EXCEPTION (S390_CC_NC, "OverflowException");
3701                 }
3702                         break;
3703                 case OP_SUB_OVF_CARRY: {
3704                         CHECK_SRCDST_NCOM;
3705                         s390_lhi  (code, s390_r0, 0);
3706                         s390_lr   (code, s390_r1, s390_r0);
3707                         s390_slbr (code, s390_r0, s390_r1);
3708                         s390_sr   (code, ins->dreg, src2);
3709                         EMIT_COND_SYSTEM_EXCEPTION (S390_CC_OV, "OverflowException");
3710                         s390_ar   (code, ins->dreg, s390_r0);
3711                         EMIT_COND_SYSTEM_EXCEPTION (S390_CC_OV, "OverflowException");
3712                 }
3713                         break;
3714                 case OP_SUB_OVF_UN_CARRY: {
3715                         CHECK_SRCDST_NCOM;
3716                         s390_slbr (code, ins->dreg, src2);
3717                         EMIT_COND_SYSTEM_EXCEPTION (S390_CC_NC, "OverflowException");
3718                 }
3719                         break;
3720                 case CEE_AND: {
3721                         if (ins->sreg1 == ins->dreg) {
3722                                 s390_nr   (code, ins->dreg, ins->sreg2);
3723                         } 
3724                         else { 
3725                                 if (ins->sreg2 == ins->dreg) { 
3726                                         s390_nr  (code, ins->dreg, ins->sreg1);
3727                                 }
3728                                 else { 
3729                                         s390_lr  (code, ins->dreg, ins->sreg1);
3730                                         s390_nr  (code, ins->dreg, ins->sreg2);
3731                                 }
3732                         }
3733                 }
3734                         break;
3735                 case OP_AND_IMM: {
3736                         if (s390_is_uimm16 (ins->inst_imm)) {
3737                                 s390_lhi  (code, s390_r0, ins->inst_imm);
3738                                 if (ins->dreg != ins->sreg1) {
3739                                         s390_lr   (code, ins->dreg, ins->sreg1);
3740                                 }
3741                                 s390_nr   (code, ins->dreg, s390_r0);
3742                         } else {
3743                                 s390_basr (code, s390_r13, 0);
3744                                 s390_j    (code, 4);
3745                                 s390_word (code, ins->inst_imm);
3746                                 if (ins->dreg != ins->sreg1) {
3747                                         s390_lr   (code, ins->dreg, ins->sreg1);
3748                                 }
3749                                 s390_n    (code, ins->dreg, 0, s390_r13, 4);
3750                         }
3751                 }
3752                         break;
3753                 case CEE_DIV: {
3754                         s390_lr   (code, s390_r0, ins->sreg1);
3755                         s390_srda (code, s390_r0, 0, 32);
3756                         s390_dr   (code, s390_r0, ins->sreg2);
3757                         s390_lr   (code, ins->dreg, s390_r1);
3758                 }
3759                         break;
3760                 case CEE_DIV_UN: {
3761                         s390_lr   (code, s390_r0, ins->sreg1);
3762                         s390_srdl (code, s390_r0, 0, 32);
3763                         s390_dlr  (code, s390_r0, ins->sreg2);
3764                         s390_lr   (code, ins->dreg, s390_r1);
3765                 }
3766                         break;
3767                 case OP_DIV_IMM: {
3768                         if (s390_is_uimm16 (ins->inst_imm)) {
3769                                 s390_lhi  (code, s390_r13, ins->inst_imm);
3770                                 s390_lr   (code, s390_r0, ins->sreg1);
3771                         } else {
3772                                 s390_basr (code, s390_r13, 0);
3773                                 s390_j    (code, 4);
3774                                 s390_word (code, ins->inst_imm);
3775                                 s390_lr   (code, s390_r0, ins->sreg1);
3776                                 s390_l    (code, s390_r13, 0, s390_r13, 4);
3777                         }
3778                         s390_srda (code, s390_r0, 0, 32);
3779                         s390_dr   (code, s390_r0, s390_r13);
3780                         s390_lr   (code, ins->dreg, s390_r1);
3781                 }
3782                         break;
3783                 case CEE_REM: {
3784                         s390_lr   (code, s390_r0, ins->sreg1);
3785                         s390_srda (code, s390_r0, 0, 32);
3786                         s390_dr   (code, s390_r0, ins->sreg2);
3787                         s390_lr   (code, ins->dreg, s390_r0);
3788                         break;
3789                 case CEE_REM_UN:
3790                         s390_lr   (code, s390_r0, ins->sreg1);
3791                         s390_srdl (code, s390_r0, 0, 32);
3792                         s390_dlr  (code, s390_r0, ins->sreg2);
3793                         s390_lr   (code, ins->dreg, s390_r0);
3794                 }
3795                         break;
3796                 case OP_REM_IMM: {
3797                         if (s390_is_uimm16 (ins->inst_imm)) {
3798                                 s390_lhi  (code, s390_r13, ins->inst_imm);
3799                                 s390_lr   (code, s390_r0, ins->sreg1);
3800                         } else {
3801                                 s390_basr (code, s390_r13, 0);
3802                                 s390_j    (code, 4);
3803                                 s390_word (code, ins->inst_imm);
3804                                 s390_lr   (code, s390_r0, ins->sreg1);
3805                                 s390_l    (code, s390_r13, 0, s390_r13, 4);
3806                         }
3807                         s390_srda (code, s390_r0, 0, 32);
3808                         s390_dr   (code, s390_r0, s390_r13);
3809                         s390_lr   (code, ins->dreg, s390_r0);
3810                 }
3811                         break;
3812                 case CEE_OR: {
3813                         if (ins->sreg1 == ins->dreg) {
3814                                 s390_or   (code, ins->dreg, ins->sreg2);
3815                         } 
3816                         else { 
3817                                 if (ins->sreg2 == ins->dreg) { 
3818                                         s390_or  (code, ins->dreg, ins->sreg1);
3819                                 }
3820                                 else { 
3821                                         s390_lr  (code, ins->dreg, ins->sreg1);
3822                                         s390_or  (code, ins->dreg, ins->sreg2);
3823                                 }
3824                         }
3825                 }
3826                         break;
3827                 case OP_OR_IMM: {
3828                         if (s390_is_uimm16 (ins->inst_imm)) {
3829                                 s390_lhi  (code, s390_r0, ins->inst_imm);
3830                                 if (ins->dreg != ins->sreg1) {
3831                                         s390_lr   (code, ins->dreg, ins->sreg1);
3832                                 }
3833                                 s390_or   (code, ins->dreg, s390_r0);
3834                         } else {
3835                                 s390_basr (code, s390_r13, 0);
3836                                 s390_j    (code, 4);
3837                                 s390_word (code, ins->inst_imm);
3838                                 if (ins->dreg != ins->sreg1) {
3839                                         s390_lr   (code, ins->dreg, ins->sreg1);
3840                                 }
3841                                 s390_o    (code, ins->dreg, 0, s390_r13, 4);
3842                         }
3843                 }
3844                         break;
3845                 case CEE_XOR: {
3846                         if (ins->sreg1 == ins->dreg) {
3847                                 s390_xr   (code, ins->dreg, ins->sreg2);
3848                         } 
3849                         else { 
3850                                 if (ins->sreg2 == ins->dreg) { 
3851                                         s390_xr  (code, ins->dreg, ins->sreg1);
3852                                 }
3853                                 else { 
3854                                         s390_lr  (code, ins->dreg, ins->sreg1);
3855                                         s390_xr  (code, ins->dreg, ins->sreg2);
3856                                 }
3857                         }
3858                 }
3859                         break;
3860                 case OP_XOR_IMM: {
3861                         if (s390_is_uimm16 (ins->inst_imm)) {
3862                                 s390_lhi  (code, s390_r0, ins->inst_imm);
3863                                 if (ins->dreg != ins->sreg1) {
3864                                         s390_lr   (code, ins->dreg, ins->sreg1);
3865                                 }
3866                                 s390_xr   (code, ins->dreg, s390_r0);
3867                         } else {
3868                                 s390_basr (code, s390_r13, 0);
3869                                 s390_j    (code, 4);
3870                                 s390_word (code, ins->inst_imm);
3871                                 if (ins->dreg != ins->sreg1) {
3872                                         s390_lr   (code, ins->dreg, ins->sreg1);
3873                                 }
3874                                 s390_x    (code, ins->dreg, 0, s390_r13, 4);
3875                         }
3876                 }
3877                         break;
3878                 case CEE_SHL: {
3879                         CHECK_SRCDST_NCOM;
3880                         s390_sll  (code, ins->dreg, src2, 0);
3881                 }
3882                         break;
3883                 case OP_SHL_IMM: {
3884                         if (ins->sreg1 != ins->dreg) {
3885                                 s390_lr   (code, ins->dreg, ins->sreg1);
3886                         }
3887                         s390_sll  (code, ins->dreg, 0, (ins->inst_imm & 0x1f));
3888                 }
3889                         break;
3890                 case CEE_SHR: {
3891                         CHECK_SRCDST_NCOM;
3892                         s390_sra  (code, ins->dreg, src2, 0);
3893                 }
3894                         break;
3895                 case OP_SHR_IMM: {
3896                         if (ins->sreg1 != ins->dreg) {
3897                                 s390_lr   (code, ins->dreg, ins->sreg1);
3898                         }
3899                         s390_sra  (code, ins->dreg, 0, (ins->inst_imm & 0x1f));
3900                 }
3901                         break;
3902                 case OP_SHR_UN_IMM: {
3903                         if (ins->sreg1 != ins->dreg) {
3904                                 s390_lr   (code, ins->dreg, ins->sreg1);
3905                         }
3906                         s390_srl  (code, ins->dreg, 0, (ins->inst_imm & 0x1f));
3907                 }
3908                         break;
3909                 case CEE_SHR_UN: {
3910                         CHECK_SRCDST_NCOM;
3911                         s390_srl  (code, ins->dreg, src2, 0);
3912                 }
3913                         break;
3914                 case CEE_NOT: {
3915                         if (ins->sreg1 != ins->dreg) {
3916                                 s390_lr   (code, ins->dreg, ins->sreg1);
3917                         }
3918                         s390_lhi (code, s390_r0, -1);
3919                         s390_xr  (code, ins->dreg, s390_r0);
3920                 }
3921                         break;
3922                 case CEE_NEG: {
3923                         s390_lcr (code, ins->dreg, ins->sreg1);
3924                 }
3925                         break;
3926                 case CEE_MUL: {
3927                         if (ins->sreg1 == ins->dreg) {
3928                                 s390_msr  (code, ins->dreg, ins->sreg2);
3929                         } 
3930                         else { 
3931                                 if (ins->sreg2 == ins->dreg) { 
3932                                         s390_msr (code, ins->dreg, ins->sreg1);
3933                                 }
3934                                 else { 
3935                                         s390_lr  (code, ins->dreg, ins->sreg1);
3936                                         s390_msr (code, ins->dreg, ins->sreg2);
3937                                 }
3938                         }
3939                 }
3940                         break;
3941                 case OP_MUL_IMM: {
3942                         if (s390_is_uimm16 (ins->inst_imm)) {
3943                                 s390_lhi  (code, s390_r13, ins->inst_imm);
3944                         } else {
3945                                 s390_basr (code, s390_r13, 0);
3946                                 s390_j    (code, 4);
3947                                 s390_word (code, ins->inst_imm);
3948                                 if (ins->dreg != ins->sreg1) {
3949                                         s390_lr   (code, ins->dreg, ins->sreg1);
3950                                 }
3951                                 s390_l    (code, s390_r13, 0, s390_r13, 4);
3952                         }
3953                         s390_msr  (code, ins->dreg, s390_r13);
3954                 }
3955                         break;
3956                 case CEE_MUL_OVF: {
3957                         short int *o[2];
3958                         s390_ltr  (code, s390_r1, ins->sreg1);
3959                         s390_jz   (code, 0); CODEPTR(code, o[0]);
3960                         s390_ltr  (code, s390_r0, ins->sreg2);
3961                         s390_jnz  (code, 6);
3962                         s390_lhi  (code, s390_r1, 0);
3963                         s390_j    (code, 0); CODEPTR(code, o[1]);
3964                         s390_xr   (code, s390_r0, s390_r1);
3965                         s390_msr  (code, s390_r1, ins->sreg2);
3966                         s390_xr   (code, s390_r0, s390_r1);
3967                         s390_srl  (code, s390_r0, 0, 31);
3968                         s390_ltr  (code, s390_r0, s390_r0);
3969                         EMIT_COND_SYSTEM_EXCEPTION (S390_CC_NZ, "OverflowException");
3970                         PTRSLOT   (code, o[0]); 
3971                         PTRSLOT   (code, o[1]);
3972                         s390_lr   (code, ins->dreg, s390_r1);
3973                 }
3974                         break;
3975                 case CEE_MUL_OVF_UN: {
3976                         s390_lhi  (code, s390_r0, 0);
3977                         s390_lr   (code, s390_r1, ins->sreg1);
3978                         s390_mlr  (code, s390_r0, ins->sreg2);
3979                         s390_ltr  (code, s390_r0, s390_r0);
3980                         EMIT_COND_SYSTEM_EXCEPTION (S390_CC_NZ, "OverflowException");
3981                         s390_lr   (code, ins->dreg, s390_r1);
3982                 }
3983                         break;
3984                 case OP_LMUL: {
3985                         s390_l    (code, s390_r0, 0, ins->sreg1, 4);
3986                         s390_srda (code, s390_r0, 0, 32);
3987                         s390_m    (code, s390_r0, 0, ins->sreg2, 4);
3988                         s390_l    (code, s390_r0, 0, ins->sreg1, 4);
3989                         s390_srl  (code, s390_r0, 0, 31);
3990                         s390_a    (code, s390_r0, 0, ins->sreg1, 0);
3991                         s390_l    (code, s390_r13, 0, ins->sreg2, 0);
3992                         s390_srl  (code, s390_r13, 0, 31);
3993                         s390_ms   (code, s390_r13, 0, ins->sreg1, 4);
3994                         s390_ar   (code, s390_r0, s390_r13);
3995                         s390_st   (code, s390_r0, 0, ins->dreg, 0);
3996                         s390_st   (code, s390_r1, 0, ins->dreg, 4);
3997                 }
3998                         break;  
3999                 case OP_ICONST:
4000                 case OP_SETREGIMM: {
4001                         if (s390_is_uimm16(ins->inst_c0)) {
4002                                 s390_lhi  (code, ins->dreg, ins->inst_c0);
4003                         } else {
4004                                 s390_basr (code, s390_r13, 0);
4005                                 s390_j    (code, 4);
4006                                 s390_word (code, ins->inst_c0);
4007                                 s390_l    (code, ins->dreg, 0, s390_r13, 4);
4008                         }
4009                 }
4010                         break;
4011                 case OP_AOTCONST: {
4012                         s390_basr (code, s390_r13, 0);
4013                         s390_j    (code, 4);
4014                         mono_add_patch_info (cfg, code - cfg->native_code, 
4015                                 (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
4016                         s390_word (code, 0);
4017                         s390_l    (code,ins->dreg, 0, s390_r13, 4);
4018                 }
4019                         break;
4020                 case CEE_CONV_I4:
4021                 case CEE_CONV_U4:
4022                 case OP_MOVE:
4023                 case OP_SETREG: {
4024                         if (ins->dreg != ins->sreg1) {
4025                                 s390_lr (code, ins->dreg, ins->sreg1);
4026                         }
4027                 }
4028                         break;
4029                 case OP_SETLRET: {
4030                         int saved = ins->sreg1;
4031                         if (ins->sreg1 == s390_r2) {
4032                                 s390_lr (code, s390_r0, ins->sreg1);
4033                                 saved = s390_r0;
4034                         }
4035                         if (ins->sreg2 != s390_r2)
4036                                 s390_lr (code, s390_r2, ins->sreg2);
4037                         if (saved != s390_r3)
4038                                 s390_lr (code, s390_r3, saved);
4039                         break;
4040                 }
4041                 case OP_SETFREG:
4042                 case OP_FMOVE: {
4043                         if (ins->dreg != ins->sreg1) {
4044                                 s390_ldr   (code, ins->dreg, ins->sreg1);
4045                         }
4046                 }
4047                         break;
4048                 case OP_S390_SETF4RET: {
4049                         s390_ledbr (code, ins->dreg, ins->sreg1);
4050                 }
4051                         break;
4052                 case OP_TLS_GET: {
4053                         if (s390_is_uimm16 (ins->inst_offset)) {
4054                                 s390_lhi (code, s390_r13, ins->inst_offset);
4055                         } else {
4056                                 s390_bras (code, s390_r13, 0);
4057                                 s390_j    (code, 4);
4058                                 s390_word (code, ins->inst_offset);
4059                                 s390_l    (code, s390_r13, 0, s390_r13, 4);
4060                         }
4061                         s390_ear (code, s390_r1, 0);
4062                         s390_l   (code, ins->dreg, s390_r13, s390_r1, 0);
4063                 }
4064                         break;
4065                 case OP_FCONV_TO_R4: {
4066                         if ((ins->next) &&
4067                             (ins->next->opcode != OP_STORER4_MEMBASE_REG))
4068                                 s390_ledbr (code, ins->dreg, ins->sreg1);
4069                 }
4070                         break;
4071                 case CEE_JMP: {
4072                         int iParm, fParm, pOffset;
4073                         if (cfg->method->save_lmf)
4074                                 restoreLMF(code, cfg->frame_reg, cfg->stack_usage);
4075
4076                         if (cfg->flags & MONO_CFG_HAS_TAIL) {
4077                                 pOffset = S390_PARM_SAVE_OFFSET;
4078                                 s390_l  (code, s390_r13, 0, STK_BASE, 0);
4079                                 for (iParm = s390_r2; 
4080                                      iParm <= s390_r5; 
4081                                      iParm++, pOffset+sizeof(gint32)) {
4082                                         if (cfg->used_int_regs & (1 << iParm))
4083                                                 s390_l (code, iParm, 0, s390_r13, pOffset);
4084                                 }
4085                                 pOffset = S390_FLOAT_SAVE_OFFSET;
4086                                 for (fParm = 0; 
4087                                      fParm < 4; 
4088                                      fParm++, pOffset+sizeof(double)) 
4089                                         s390_ld (code, fParm, 0, s390_r13, pOffset);
4090                         }
4091
4092                         code = backUpStackPtr(cfg, code);
4093                         s390_l   (code, s390_r14, 0, STK_BASE, S390_RET_ADDR_OFFSET);
4094                         mono_add_patch_info (cfg, code - cfg->native_code,
4095                                              MONO_PATCH_INFO_METHOD_JUMP,
4096                                              ins->inst_p0);
4097                         s390_jcl (code, S390_CC_UN, 0);
4098                 }
4099                         break;
4100                 case OP_CHECK_THIS: {
4101                         /* ensure ins->sreg1 is not NULL */
4102                         s390_icm (code, s390_r0, 15, ins->sreg1, 0);
4103                 }
4104                         break;
4105                 case OP_ARGLIST: {
4106                         int offset = cfg->sig_cookie + cfg->stack_usage;
4107
4108                         if (s390_is_uimm16 (offset))
4109                                 s390_lhi  (code, s390_r0, offset);
4110                         else {
4111                                 s390_basr (code, s390_r13, 0);
4112                                 s390_j    (code, 4);
4113                                 s390_word (code, offset);
4114                                 s390_l    (code, s390_r0, 0, s390_r13, 0);
4115                         }
4116                         s390_ar   (code, s390_r0, cfg->frame_reg);
4117                         s390_st   (code, s390_r0, 0, ins->sreg1, 0);
4118                 }
4119                         break;
4120                 case OP_FCALL: {
4121                         call = (MonoCallInst*)ins;
4122                         if (ins->flags & MONO_INST_HAS_METHOD)
4123                                 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, 
4124                                                      call->method);
4125                         else
4126                                 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, 
4127                                                      call->fptr);
4128                         s390_brasl (code, s390_r14, 0);
4129                         if (call->signature->ret->type == MONO_TYPE_R4)
4130                                 s390_ldebr (code, s390_f0, s390_f0);
4131                 }
4132                         break;
4133                 case OP_LCALL:
4134                 case OP_VCALL:
4135                 case OP_VOIDCALL:
4136                 case CEE_CALL: {
4137                         call = (MonoCallInst*)ins;
4138                         if (ins->flags & MONO_INST_HAS_METHOD)
4139                                 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
4140                         else
4141                                 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
4142                         s390_brasl (code, s390_r14, 0);
4143                 }
4144                         break;
4145                 case OP_FCALL_REG: {
4146                         call = (MonoCallInst*)ins;
4147                         s390_lr   (code, s390_r1, ins->sreg1);
4148                         s390_basr (code, s390_r14, s390_r1);
4149                         if (call->signature->ret->type == MONO_TYPE_R4)
4150                                 s390_ldebr (code, s390_f0, s390_f0);
4151                 }
4152                         break;
4153                 case OP_LCALL_REG:
4154                 case OP_VCALL_REG:
4155                 case OP_VOIDCALL_REG:
4156                 case OP_CALL_REG: {
4157                         s390_lr   (code, s390_r1, ins->sreg1);
4158                         s390_basr (code, s390_r14, s390_r1);
4159                 }
4160                         break;
4161                 case OP_FCALL_MEMBASE: {
4162                         call = (MonoCallInst*)ins;
4163                         s390_l    (code, s390_r1, 0, ins->sreg1, ins->inst_offset);
4164                         s390_basr (code, s390_r14, s390_r1);
4165                         if (call->signature->ret->type == MONO_TYPE_R4)
4166                                 s390_ldebr (code, s390_f0, s390_f0);
4167                 }
4168                         break;
4169                 case OP_LCALL_MEMBASE:
4170                 case OP_VCALL_MEMBASE:
4171                 case OP_VOIDCALL_MEMBASE:
4172                 case OP_CALL_MEMBASE: {
4173                         s390_l    (code, s390_r1, 0, ins->sreg1, ins->inst_offset);
4174                         s390_basr (code, s390_r14, s390_r1);
4175                 }
4176                         break;
4177                 case OP_OUTARG: 
4178                         g_assert_not_reached ();
4179                         break;
4180                 case OP_LOCALLOC: {
4181                         int alloca_skip = S390_MINIMAL_STACK_SIZE + cfg->param_area + 
4182                                           S390_STACK_ALIGNMENT - 1;
4183                         int area_offset = S390_ALIGN(alloca_skip, S390_STACK_ALIGNMENT);
4184                         s390_lr   (code, s390_r1, ins->sreg1);
4185                         if (ins->flags & MONO_INST_INIT)
4186                                 s390_lr   (code, s390_r0, ins->sreg1);
4187                         s390_ahi  (code, s390_r1, 14);
4188                         s390_srl  (code, s390_r1, 0, 3);
4189                         s390_sll  (code, s390_r1, 0, 3);
4190                         s390_l    (code, s390_r13, 0, STK_BASE, 0);
4191                         s390_lcr  (code, s390_r1, s390_r1);
4192                         s390_la   (code, STK_BASE, STK_BASE, s390_r1, 0);
4193                         s390_st   (code, s390_r13, 0, STK_BASE, 0);
4194                         s390_la   (code, ins->dreg, 0, STK_BASE, area_offset);
4195                         s390_srl  (code, ins->dreg, 0, 3);
4196                         s390_sll  (code, ins->dreg, 0, 3);
4197                         if (ins->flags & MONO_INST_INIT) {
4198                                 s390_lr   (code, s390_r1, s390_r0);
4199                                 s390_lr   (code, s390_r0, ins->dreg);
4200                                 s390_lr   (code, s390_r14, s390_r12);
4201                                 s390_lhi  (code, s390_r13, 0);
4202                                 s390_mvcle(code, s390_r0, s390_r12, 0, 0);
4203                                 s390_jo   (code, -2);
4204                                 s390_lr   (code, s390_r12, s390_r14);
4205                         }
4206                 }
4207                         break;
4208                 case CEE_RET: {
4209                         s390_br  (code, s390_r14);
4210                 }
4211                         break;
4212                 case CEE_THROW: {
4213                         s390_lr (code, s390_r2, ins->sreg1);
4214                         mono_add_patch_info (cfg, code-cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
4215                                              (gpointer)"mono_arch_throw_exception");
4216                         s390_brasl (code, s390_r14, 0);
4217                 }
4218                         break;
4219                 case OP_RETHROW: {
4220                         s390_lr (code, s390_r2, ins->sreg1);
4221                         mono_add_patch_info (cfg, code-cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
4222                                              (gpointer)"mono_arch_rethrow_exception");
4223                         s390_brasl (code, s390_r14, 0);
4224                 }
4225                         break;
4226                 case OP_START_HANDLER: {
4227                         if (s390_is_uimm12 (ins->inst_left->inst_offset)) {
4228                                 s390_st   (code, s390_r14, 0, 
4229                                            ins->inst_left->inst_basereg, 
4230                                            ins->inst_left->inst_offset);
4231                         } else {
4232                                 s390_basr (code, s390_r13, 0);
4233                                 s390_j    (code, 4);
4234                                 s390_word (code, ins->inst_left->inst_offset);
4235                                 s390_l    (code, s390_r13, 0, s390_r13, 4);
4236                                 s390_st   (code, s390_r14, s390_r13, 
4237                                            ins->inst_left->inst_basereg, 0);
4238                         }
4239                 }
4240                         break;
4241                 case OP_ENDFILTER: {
4242                         if (ins->sreg1 != s390_r2)
4243                                 s390_lr (code, s390_r2, ins->sreg1);
4244                         if (s390_is_uimm12 (ins->inst_left->inst_offset)) {
4245                                 s390_l  (code, s390_r14, 0, ins->inst_left->inst_basereg,
4246                                          ins->inst_left->inst_offset);
4247                         } else {
4248                                 s390_basr (code, s390_r13, 0);
4249                                 s390_j    (code, 4);
4250                                 s390_word (code, ins->inst_left->inst_offset);
4251                                 s390_l    (code, s390_r13, 0, s390_r13, 4);
4252                                 s390_l    (code, s390_r14, s390_r13, 
4253                                            ins->inst_left->inst_basereg, 0);
4254                         }
4255                         s390_br  (code, s390_r14);
4256                 }
4257                         break;
4258                 case CEE_ENDFINALLY: {
4259                         if (s390_is_uimm12 (ins->inst_left->inst_offset)) {
4260                                 s390_l  (code, s390_r14, 0, ins->inst_left->inst_basereg,
4261                                          ins->inst_left->inst_offset);
4262                         } else {
4263                                 s390_basr (code, s390_r13, 0);
4264                                 s390_j    (code, 4);
4265                                 s390_word (code, ins->inst_left->inst_offset);
4266                                 s390_l    (code, s390_r13, 0, s390_r13, 4);
4267                                 s390_l    (code, s390_r14, s390_r13, 
4268                                            ins->inst_left->inst_basereg, 0);
4269                         }
4270                         s390_br  (code, s390_r14);
4271                 }
4272                         break;
4273                 case OP_CALL_HANDLER: {
4274                         mono_add_patch_info (cfg, code-cfg->native_code, 
4275                                              MONO_PATCH_INFO_BB, ins->inst_target_bb);
4276                         s390_brasl (code, s390_r14, 0);
4277                 }
4278                         break;
4279                 case OP_LABEL: {
4280                         ins->inst_c0 = code - cfg->native_code;
4281                 }
4282                         break;
4283                 case CEE_BR: 
4284                         EMIT_UNCOND_BRANCH(ins);
4285                         break;
4286                 case OP_BR_REG: {
4287                         s390_br  (code, ins->sreg1);
4288                 }
4289                         break;
4290                 case OP_CEQ: {
4291                         s390_lhi (code, ins->dreg, 1);
4292                         s390_jz  (code, 4);
4293                         s390_lhi (code, ins->dreg, 0);
4294                 }
4295                         break;
4296                 case OP_CLT: {
4297                         s390_lhi (code, ins->dreg, 1);
4298                         s390_jl  (code, 4);
4299                         s390_lhi (code, ins->dreg, 0);
4300                 }
4301                         break;
4302                 case OP_CLT_UN: {
4303                         s390_lhi (code, ins->dreg, 1);
4304                         s390_jlo (code, 4);
4305                         s390_lhi (code, ins->dreg, 0);
4306                 }
4307                         break;
4308                 case OP_CGT: {
4309                         s390_lhi (code, ins->dreg, 1);
4310                         s390_jh  (code, 4);
4311                         s390_lhi (code, ins->dreg, 0);
4312                 }
4313                         break;
4314                 case OP_CGT_UN: {
4315                         s390_lhi (code, ins->dreg, 1);
4316                         s390_jho (code, 4);
4317                         s390_lhi (code, ins->dreg, 0);
4318                 }
4319                         break;
4320                 case OP_COND_EXC_EQ:
4321                         EMIT_COND_SYSTEM_EXCEPTION (S390_CC_EQ, ins->inst_p1);
4322                         break;
4323                 case OP_COND_EXC_NE_UN:
4324                         EMIT_COND_SYSTEM_EXCEPTION (S390_CC_NE, ins->inst_p1);
4325                         break;
4326                 case OP_COND_EXC_LT:
4327                 case OP_COND_EXC_LT_UN:
4328                         EMIT_COND_SYSTEM_EXCEPTION (S390_CC_LT, ins->inst_p1);
4329                         break;
4330                 case OP_COND_EXC_GT:
4331                 case OP_COND_EXC_GT_UN:
4332                         EMIT_COND_SYSTEM_EXCEPTION (S390_CC_GT, ins->inst_p1);
4333                         break;
4334                 case OP_COND_EXC_GE:
4335                 case OP_COND_EXC_GE_UN:
4336                         EMIT_COND_SYSTEM_EXCEPTION (S390_CC_GE, ins->inst_p1);
4337                         break;
4338                 case OP_COND_EXC_LE:
4339                 case OP_COND_EXC_LE_UN:
4340                         EMIT_COND_SYSTEM_EXCEPTION (S390_CC_LE, ins->inst_p1);
4341                         break;
4342                 case OP_COND_EXC_OV:
4343                         EMIT_COND_SYSTEM_EXCEPTION (S390_CC_OV, ins->inst_p1);
4344                         break;
4345                 case OP_COND_EXC_NO:
4346                         EMIT_COND_SYSTEM_EXCEPTION (S390_CC_NO, ins->inst_p1);
4347                         break;
4348                 case OP_COND_EXC_C:
4349                         EMIT_COND_SYSTEM_EXCEPTION (S390_CC_CY, ins->inst_p1);
4350                         break;
4351                 case OP_COND_EXC_NC:
4352                         EMIT_COND_SYSTEM_EXCEPTION (S390_CC_NC, ins->inst_p1);
4353                         break;
4354                 case CEE_BEQ:
4355                         EMIT_COND_BRANCH (ins, S390_CC_EQ);
4356                         break;  
4357                 case CEE_BNE_UN:
4358                         EMIT_COND_BRANCH (ins, S390_CC_NE);
4359                         break;  
4360                 case CEE_BLT:
4361                 case CEE_BLT_UN:
4362                         EMIT_COND_BRANCH (ins, S390_CC_LT);
4363                         break;  
4364                 case CEE_BGT:
4365                 case CEE_BGT_UN:
4366                         EMIT_COND_BRANCH (ins, S390_CC_GT);
4367                         break;  
4368                 case CEE_BGE:
4369                 case CEE_BGE_UN:
4370                         EMIT_COND_BRANCH (ins, S390_CC_GE);
4371                         break;  
4372                 case CEE_BLE:
4373                 case CEE_BLE_UN:
4374                         EMIT_COND_BRANCH (ins, S390_CC_LE);
4375                         break;
4376
4377                 /* floating point opcodes */
4378                 case OP_R8CONST: {
4379                         if (*((float *) ins->inst_p0) == 0) {
4380                                 s390_lzdr (code, ins->dreg);
4381                         } else {
4382                                 s390_basr  (code, s390_r13, 0);
4383                                 s390_j     (code, 4);
4384                                 s390_word  (code, ins->inst_p0);
4385                                 s390_l     (code, s390_r13, 0, s390_r13, 4);
4386                                 s390_ld    (code, ins->dreg, 0, s390_r13, 0);
4387                         }
4388                 }
4389                         break;
4390                 case OP_R4CONST: {
4391                         if (*((float *) ins->inst_p0) == 0) {
4392                                 s390_lzdr (code, ins->dreg);
4393                         } else {
4394                                 s390_basr (code, s390_r13, 0);
4395                                 s390_j    (code, 4);
4396                                 s390_word (code, ins->inst_p0);
4397                                 s390_l    (code, s390_r13, 0, s390_r13, 4);
4398                                 s390_ldeb (code, ins->dreg, 0, s390_r13, 0);
4399                         }
4400                 }
4401                         break;
4402                 case OP_STORER8_MEMBASE_REG: {
4403                         if (s390_is_uimm12(ins->inst_offset)) {
4404                                 s390_std  (code, ins->sreg1, 0, ins->inst_destbasereg, ins->inst_offset);
4405                         } else {
4406                                 s390_basr (code, s390_r13, 0);
4407                                 s390_j    (code, 4);
4408                                 s390_word (code, ins->inst_offset);
4409                                 s390_l    (code, s390_r13, 0, s390_r13, 4);
4410                                 s390_std  (code, ins->sreg1, s390_r13, ins->inst_destbasereg, 0);
4411                         }
4412                 }
4413                         break;
4414                 case OP_LOADR8_MEMBASE: {
4415                         if (s390_is_uimm12(ins->inst_offset)) {
4416                                 s390_ld   (code, ins->dreg, 0, ins->inst_basereg, ins->inst_offset);
4417                         } else {
4418                                 s390_basr (code, s390_r13, 0);
4419                                 s390_j    (code, 4);
4420                                 s390_word (code, ins->inst_offset);
4421                                 s390_l    (code, s390_r13, 0, s390_r13, 4);
4422                                 s390_ld   (code, ins->dreg, s390_r13, ins->inst_basereg, 0);
4423                         }
4424                 }
4425                         break;
4426                 case OP_STORER4_MEMBASE_REG: {
4427                         if (s390_is_uimm12(ins->inst_offset)) {
4428                                 s390_ledbr(code, s390_f15, ins->sreg1);
4429                                 s390_ste  (code, s390_f15, 0, ins->inst_destbasereg, ins->inst_offset);
4430                         } else {
4431                                 s390_basr (code, s390_r13, 0);
4432                                 s390_j    (code, 4);
4433                                 s390_word (code, ins->inst_offset);
4434                                 s390_l    (code, s390_r13, 0, s390_r13, 4);
4435                                 s390_ledbr(code, s390_f15, ins->sreg1);
4436                                 s390_ste  (code, s390_f15, s390_r13, ins->inst_destbasereg, 0);
4437                         }
4438                 }
4439                         break;
4440                 case OP_LOADR4_MEMBASE: {
4441                         if (s390_is_uimm12(ins->inst_offset)) {
4442                                 s390_ldeb (code, ins->dreg, 0, ins->inst_basereg, ins->inst_offset);
4443                         } else {
4444                                 s390_basr (code, s390_r13, 0);
4445                                 s390_j    (code, 4);
4446                                 s390_word (code, ins->inst_offset);
4447                                 s390_l    (code, s390_r13, 0, s390_r13, 4);
4448                                 s390_ldeb (code, ins->dreg, s390_r13, ins->inst_basereg, 0);
4449                         }
4450                 }
4451                         break;
4452                 case CEE_CONV_R_UN: {
4453                         s390_cdfbr (code, ins->dreg, ins->sreg1);
4454                         s390_ltr   (code, ins->sreg1, ins->sreg1);
4455                         s390_jnl   (code, 12);
4456                         s390_basr  (code, s390_r13, 0);
4457                         s390_j     (code, 6);
4458                         s390_word  (code, 0x41f00000);
4459                         s390_word  (code, 0);
4460                         s390_adb   (code, ins->dreg, 0, s390_r13, 4);
4461                 }
4462                         break;
4463                 case CEE_CONV_R4: {
4464                         s390_cdfbr (code, ins->dreg, ins->sreg1);
4465                 }
4466                         break;
4467                 case CEE_CONV_R8: {
4468                         s390_cdfbr (code, ins->dreg, ins->sreg1);
4469                 }
4470                         break;
4471                 case OP_FCONV_TO_I1:
4472                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4473                         break;
4474                 case OP_FCONV_TO_U1:
4475                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4476                         break;
4477                 case OP_FCONV_TO_I2:
4478                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4479                         break;
4480                 case OP_FCONV_TO_U2:
4481                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4482                         break;
4483                 case OP_FCONV_TO_I4:
4484                 case OP_FCONV_TO_I:
4485                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4486                         break;
4487                 case OP_FCONV_TO_U4:
4488                 case OP_FCONV_TO_U:
4489                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4490                         break;
4491                 case OP_FCONV_TO_I8:
4492                 case OP_FCONV_TO_U8:
4493                         g_assert_not_reached ();
4494                         /* Implemented as helper calls */
4495                         break;
4496                 case OP_LCONV_TO_R_UN:
4497                         g_assert_not_reached ();
4498                         /* Implemented as helper calls */
4499                         break;
4500                 case OP_LCONV_TO_OVF_I: {
4501                         /* Valid ints: 0xffffffff:8000000 to 00000000:0x7f000000 */
4502                         short int *o[5];
4503                         s390_ltr  (code, ins->sreg1, ins->sreg1);
4504                         s390_jnl  (code, 0); CODEPTR(code, o[0]);
4505                         s390_ltr  (code, ins->sreg2, ins->sreg2);
4506                         s390_jnl  (code, 0); CODEPTR(code, o[1]);
4507                         s390_lhi  (code, s390_r13, -1);
4508                         s390_cr   (code, ins->sreg2, s390_r13);
4509                         s390_jnz  (code, 0); CODEPTR(code, o[2]);
4510                         if (ins->dreg != ins->sreg1)
4511                                 s390_lr   (code, ins->dreg, ins->sreg1);
4512                         s390_j    (code, 0); CODEPTR(code, o[3]);
4513                         PTRSLOT(code, o[0]);
4514                         s390_ltr  (code, ins->sreg2, ins->sreg2);
4515                         s390_jz   (code, 0); CODEPTR(code, o[4]);
4516                         PTRSLOT(code, o[1]);
4517                         PTRSLOT(code, o[2]);
4518                         mono_add_patch_info (cfg, code - cfg->native_code, 
4519                                              MONO_PATCH_INFO_EXC, "OverflowException");
4520                         s390_brasl (code, s390_r14, 0);
4521                         PTRSLOT(code, o[3]);
4522                         PTRSLOT(code, o[4]);
4523                 }
4524                         break;
4525                 case OP_SQRT: {
4526                         s390_sqdbr (code, ins->dreg, ins->sreg1);
4527                 }
4528                         break;
4529                 case OP_FADD: {
4530                         if (ins->dreg == ins->sreg1)
4531                                 s390_adbr (code, ins->dreg, ins->sreg2);
4532                         else {
4533                                 if (ins->dreg == ins->sreg2)
4534                                         s390_adbr (code, ins->dreg, ins->sreg1);
4535                                 else {
4536                                         s390_ldr  (code, ins->dreg, ins->sreg1);
4537                                         s390_adbr (code, ins->dreg, ins->sreg2);
4538                                 }
4539                         }
4540                 }
4541                         break;
4542                 case OP_FSUB: {
4543                         CHECK_SRCDST_NCOM_F;
4544                         s390_sdbr (code, ins->dreg, src2);
4545                 }
4546                         break;          
4547                 case OP_FMUL: {
4548                         if (ins->dreg == ins->sreg1)
4549                                 s390_mdbr (code, ins->dreg, ins->sreg2);
4550                         else {
4551                                 if (ins->dreg == ins->sreg2)
4552                                         s390_mdbr (code, ins->dreg, ins->sreg1);
4553                                 else {
4554                                         s390_ldr  (code, ins->dreg, ins->sreg1);
4555                                         s390_mdbr (code, ins->dreg, ins->sreg2);
4556                                 }
4557                         }
4558                 }
4559                         break;          
4560                 case OP_FDIV: {
4561                         CHECK_SRCDST_NCOM_F;
4562                         s390_ddbr (code, ins->dreg, src2);
4563                 }
4564                         break;          
4565                 case OP_FNEG: {
4566                         s390_lcdbr (code, ins->dreg, ins->sreg1);
4567                 }
4568                         break;          
4569                 case OP_FREM: {
4570                         CHECK_SRCDST_NCOM_F;
4571                         s390_didbr (code, ins->dreg, ins->sreg2, 5, s390_f15);
4572                 }
4573                         break;
4574                 case OP_FCOMPARE: {
4575                         s390_cdbr (code, ins->sreg1, ins->sreg2);
4576                 }
4577                         break;
4578                 case OP_FCEQ: {
4579                         s390_cdbr  (code, ins->sreg1, ins->sreg2);
4580                         s390_lhi   (code, ins->dreg, 1);
4581                         s390_je    (code, 4);
4582                         s390_lhi   (code, ins->dreg, 0);
4583                 }
4584                         break;
4585                 case OP_FCLT: {
4586                         s390_cdbr  (code, ins->sreg1, ins->sreg2);
4587                         s390_lhi   (code, ins->dreg, 1);
4588                         s390_jl    (code, 4);
4589                         s390_lhi   (code, ins->dreg, 0);
4590                 }
4591                         break;
4592                 case OP_FCLT_UN: {
4593                         s390_cdbr  (code, ins->sreg1, ins->sreg2);
4594                         s390_lhi   (code, ins->dreg, 1);
4595                         s390_jlo   (code, 4);
4596                         s390_lhi   (code, ins->dreg, 0);
4597                 }
4598                         break;
4599                 case OP_FCGT: {
4600                         s390_cdbr  (code, ins->sreg1, ins->sreg2);
4601                         s390_lhi   (code, ins->dreg, 1);
4602                         s390_jh    (code, 4);
4603                         s390_lhi   (code, ins->dreg, 0);
4604                 }
4605                         break;
4606                 case OP_FCGT_UN: {
4607                         s390_cdbr  (code, ins->sreg1, ins->sreg2);
4608                         s390_lhi   (code, ins->dreg, 1);
4609                         s390_jho   (code, 4);
4610                         s390_lhi   (code, ins->dreg, 0);
4611                 }
4612                         break;
4613                 case OP_FBEQ:
4614                         EMIT_COND_BRANCH (ins, S390_CC_EQ|S390_CC_OV);
4615                         break;
4616                 case OP_FBNE_UN:
4617                         EMIT_COND_BRANCH (ins, S390_CC_NE|S390_CC_OV);
4618                         break;
4619                 case OP_FBLT:
4620                         EMIT_COND_BRANCH (ins, S390_CC_LT);
4621                         break;
4622                 case OP_FBLT_UN:
4623                         EMIT_COND_BRANCH (ins, S390_CC_LT|S390_CC_OV);
4624                         break;
4625                 case OP_FBGT:
4626                         EMIT_COND_BRANCH (ins, S390_CC_GT);
4627                         break;
4628                 case OP_FBGT_UN:
4629                         EMIT_COND_BRANCH (ins, S390_CC_GT|S390_CC_OV);
4630                         break;
4631                 case OP_FBGE:
4632                         EMIT_COND_BRANCH (ins, S390_CC_GE);
4633                         break;
4634                 case OP_FBGE_UN:
4635                         EMIT_COND_BRANCH (ins, S390_CC_GE|S390_CC_OV);
4636                         break;
4637                 case OP_FBLE:
4638                         EMIT_COND_BRANCH (ins, S390_CC_LE);
4639                         break;
4640                 case OP_FBLE_UN:
4641                         EMIT_COND_BRANCH (ins, S390_CC_LE|S390_CC_OV);
4642                         break;
4643                 case CEE_CKFINITE: {
4644                         short *o;
4645                         s390_lhi  (code, s390_r13, 0x7f);
4646                         s390_tcdb (code, ins->sreg1, 0, s390_r13, 0);
4647                         s390_jz   (code, 0); CODEPTR(code, o);
4648                         mono_add_patch_info (cfg, code - cfg->native_code, 
4649                                              MONO_PATCH_INFO_EXC, "ArithmeticException");
4650                         s390_brasl (code, s390_r14,0);
4651                         PTRSLOT(code, o);
4652                 }
4653                         break;
4654                 case OP_S390_MOVE: {
4655                         if (ins->unused > 0) {
4656                                 if (ins->unused <= 256) {
4657                                         s390_mvc  (code, ins->unused, ins->dreg, 
4658                                                    ins->inst_offset, ins->sreg1, ins->inst_imm);
4659                                 } else {
4660                                         s390_lr   (code, s390_r0, ins->dreg);
4661                                         if (s390_is_uimm16 (ins->inst_offset)) {
4662                                                 s390_ahi  (code, s390_r0, ins->inst_offset);
4663                                         } else {
4664                                                 s390_basr (code, s390_r13, 0);
4665                                                 s390_j    (code, 4);
4666                                                 s390_word (code, ins->inst_offset);
4667                                                 s390_a    (code, s390_r0, 0, s390_r13, 4);
4668                                         }
4669                                         s390_lr   (code, s390_r14, s390_r12);
4670                                         s390_lr   (code, s390_r12, ins->sreg1);
4671                                         if (s390_is_uimm16 (ins->inst_imm)) {
4672                                                 s390_ahi  (code, s390_r12, ins->inst_imm);
4673                                         } else {
4674                                                 s390_basr (code, s390_r13, 0);
4675                                                 s390_j    (code, 4);
4676                                                         s390_word (code, ins->inst_imm);
4677                                                 s390_a    (code, s390_r12, 0, s390_r13, 4);
4678                                         }
4679                                         s390_lr   (code, s390_r1, ins->sreg1);
4680                                         s390_lr   (code, s390_r13, s390_r1);
4681                                         s390_mvcle(code, s390_r0, s390_r12, 0, 0);
4682                                         s390_jo   (code, -2);
4683                                         s390_lr   (code, s390_r12, s390_r14);
4684                                 }
4685                         }
4686                 }
4687                         break;
4688                 case OP_ATOMIC_ADD_I4: {
4689                         s390_lr  (code, s390_r1, ins->sreg2);
4690                         s390_l   (code, s390_r0, 0, ins->inst_basereg, ins->inst_offset);
4691                         s390_a   (code, s390_r1, 0, ins->inst_basereg, ins->inst_offset);
4692                         s390_cs  (code, s390_r0, s390_r1, ins->inst_basereg, ins->inst_offset);
4693                         s390_jnz (code, -7);
4694                         s390_lr  (code, ins->dreg, s390_r1);
4695                 }
4696                         break;  
4697                 case OP_ATOMIC_ADD_NEW_I4: {
4698                         s390_lr  (code, s390_r1, ins->sreg2);
4699                         s390_l   (code, s390_r0, 0, ins->inst_basereg, ins->inst_offset);
4700                         s390_a   (code, s390_r1, 0, ins->inst_basereg, ins->inst_offset);
4701                         s390_cs  (code, s390_r0, s390_r1, ins->inst_basereg, ins->inst_offset);
4702                         s390_jnz (code, -7);
4703                         s390_lr  (code, ins->dreg, s390_r1);
4704                 }
4705                         break;  
4706                 case OP_ATOMIC_EXCHANGE_I4: {
4707                         s390_l   (code, s390_r0, 0, ins->inst_basereg, ins->inst_offset);
4708                         s390_cs  (code, s390_r0, ins->sreg2, ins->inst_basereg, ins->inst_offset);
4709                         s390_jnz (code, -4);
4710                         s390_lr  (code, ins->dreg, s390_r0);
4711                 }
4712                         break;  
4713                 default:
4714                         g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4715                         g_assert_not_reached ();
4716                 }
4717
4718                 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4719                         g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
4720                                    mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
4721                         g_assert_not_reached ();
4722                 }
4723                
4724                 cpos += max_len;
4725
4726                 last_ins = ins;
4727                 last_offset = offset;
4728                 
4729                 ins = ins->next;
4730         }
4731
4732         cfg->code_len = code - cfg->native_code;
4733 }
4734
4735 /*========================= End of Function ========================*/
4736
4737 /*------------------------------------------------------------------*/
4738 /*                                                                  */
4739 /* Name         - mono_arch_register_lowlevel_calls                 */
4740 /*                                                                  */
4741 /* Function     - Register routines to help with --trace operation. */
4742 /*                                                                  */
4743 /*------------------------------------------------------------------*/
4744
4745 void
4746 mono_arch_register_lowlevel_calls (void)
4747 {
4748         mono_register_jit_icall (enter_method, "mono_enter_method", NULL, TRUE);
4749         mono_register_jit_icall (leave_method, "mono_leave_method", NULL, TRUE);
4750 }
4751
4752 /*========================= End of Function ========================*/
4753
4754 /*------------------------------------------------------------------*/
4755 /*                                                                  */
4756 /* Name         - mono_arch_patch_code                              */
4757 /*                                                                  */
4758 /* Function     - Process the patch data created during the         */
4759 /*                instruction build process. This resolves jumps,   */
4760 /*                calls, variables etc.                             */
4761 /*                                                                  */
4762 /*------------------------------------------------------------------*/
4763
4764 void
4765 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, 
4766                       guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
4767 {
4768         MonoJumpInfo *patch_info;
4769
4770         for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4771                 unsigned char *ip = patch_info->ip.i + code;
4772                 gconstpointer target = NULL;
4773
4774                 target = mono_resolve_patch_target (method, domain, code, 
4775                                                     patch_info, run_cctors);
4776
4777                 switch (patch_info->type) {
4778                         case MONO_PATCH_INFO_IP:
4779                         case MONO_PATCH_INFO_EXC_NAME:
4780                         case MONO_PATCH_INFO_LDSTR:
4781                         case MONO_PATCH_INFO_TYPE_FROM_HANDLE: 
4782                         case MONO_PATCH_INFO_LDTOKEN: 
4783                         case MONO_PATCH_INFO_EXC:
4784                                 continue;
4785                         case MONO_PATCH_INFO_SWITCH: 
4786                                 /*----------------------------------*/
4787                                 /* ip points at the basr r13,0/j +4 */
4788                                 /* instruction the vtable value     */
4789                                 /* follows this (i.e. ip+6)         */
4790                                 /*----------------------------------*/
4791                                 *((gconstpointer *)(ip+6)) = target;
4792                                 target = NULL;
4793                                 continue;
4794                         case MONO_PATCH_INFO_METHODCONST:
4795                         case MONO_PATCH_INFO_CLASS:
4796                         case MONO_PATCH_INFO_IMAGE:
4797                         case MONO_PATCH_INFO_FIELD:
4798                         case MONO_PATCH_INFO_IID:
4799                                 target = S390_RELATIVE(target, ip);
4800                                 continue;
4801                         case MONO_PATCH_INFO_R4:
4802                         case MONO_PATCH_INFO_R8:
4803                         case MONO_PATCH_INFO_METHOD_REL:
4804                                 g_assert_not_reached ();
4805                                 continue;
4806                         default:
4807                                 target = S390_RELATIVE(target, ip);
4808                                 ip += 2;
4809                 }
4810                 s390_patch (ip, target);
4811         }
4812 }
4813
4814 /*========================= End of Function ========================*/
4815
4816 /*------------------------------------------------------------------*/
4817 /*                                                                  */
4818 /* Name         - mono_arch_emit_prolog                             */
4819 /*                                                                  */
4820 /* Function     - Create the instruction sequence for a function    */
4821 /*                prolog.                                           */
4822 /*                                                                  */
4823 /*------------------------------------------------------------------*/
4824
4825 guint8 *
4826 mono_arch_emit_prolog (MonoCompile *cfg)
4827 {
4828         MonoMethod *method = cfg->method;
4829         MonoBasicBlock *bb;
4830         MonoMethodSignature *sig;
4831         MonoInst *inst;
4832         int alloc_size, pos, max_offset, i;
4833         guint8 *code;
4834         CallInfo *cinfo;
4835         size_data sz;
4836         int tracing = 0;
4837         int lmfOffset;                                                          \
4838
4839         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4840                 tracing = 1;
4841
4842         cfg->code_size   = 512;
4843         cfg->native_code = code = g_malloc (cfg->code_size);
4844
4845         if (cfg->flags & MONO_CFG_HAS_TAIL) {
4846                 s390_stm (code, s390_r2, s390_r14, STK_BASE, S390_PARM_SAVE_OFFSET);
4847                 for (pos = 0; pos < 4; pos++)
4848                         s390_std (code, pos, 0, STK_BASE, 
4849                                   S390_FLOAT_SAVE_OFFSET+pos*sizeof(double));
4850         } else { 
4851                 s390_stm  (code, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
4852         }
4853
4854         if (cfg->flags & MONO_CFG_HAS_ALLOCA) {
4855                 cfg->used_int_regs |= 1 << 11;
4856         }
4857
4858         alloc_size = cfg->stack_offset;
4859
4860         cfg->stack_usage = alloc_size;
4861         s390_lr   (code, s390_r11, STK_BASE);
4862         if (s390_is_uimm16 (alloc_size)) {
4863                 s390_ahi  (code, STK_BASE, -alloc_size);
4864         } else { 
4865                 int stackSize = alloc_size;
4866                 while (stackSize > 32767) {
4867                         s390_ahi  (code, STK_BASE, -32767);
4868                         stackSize -= 32767;
4869                 }
4870                 s390_ahi  (code, STK_BASE, -stackSize);
4871         }
4872         s390_st   (code, s390_r11, 0, STK_BASE, 0);
4873
4874         if (cfg->frame_reg != STK_BASE)
4875                 s390_lr (code, s390_r11, STK_BASE);
4876
4877         /* compute max_offset in order to use short forward jumps
4878          * we always do it on s390 because the immediate displacement
4879          * for jumps is too small 
4880          */
4881         max_offset = 0;
4882         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4883                 MonoInst *ins = bb->code;
4884                 bb->max_offset = max_offset;
4885
4886                 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
4887                         max_offset += 6; 
4888
4889                 while (ins) {
4890                         max_offset += ((guint8 *)ins_spec [ins->opcode])[MONO_INST_LEN];
4891                         ins = ins->next;
4892                 }
4893         }
4894
4895         /* load arguments allocated to register from the stack */
4896         sig = mono_method_signature (method);
4897         pos = 0;
4898
4899         cinfo = calculate_sizes (sig, &sz, sig->pinvoke);
4900
4901         if (cinfo->struct_ret) {
4902                 ArgInfo *ainfo = &cinfo->ret;
4903                 inst         = cfg->ret;
4904                 inst->unused = ainfo->vtsize;
4905                 s390_st (code, ainfo->reg, 0, inst->inst_basereg, inst->inst_offset);
4906         }
4907
4908         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4909                 ArgInfo *ainfo = cinfo->args + i;
4910                 inst = cfg->varinfo [pos];
4911                 
4912                 if (inst->opcode == OP_REGVAR) {
4913                         if (ainfo->regtype == RegTypeGeneral)
4914                                 s390_lr (code, inst->dreg, ainfo->reg);
4915                         else if (ainfo->regtype == RegTypeFP) {
4916                                 if (inst->dreg != ainfo->reg) {
4917                                         if (ainfo->size == 4) {
4918                                                 s390_ledbr (code, inst->dreg, ainfo->reg);
4919                                         } else {
4920                                                 s390_ldr   (code, inst->dreg, ainfo->reg);
4921                                         }
4922                                 }
4923                         }
4924                         else if (ainfo->regtype == RegTypeBase) {
4925                                 s390_lr  (code, s390_r13, STK_BASE);
4926                                 s390_ahi (code, s390_r13, alloc_size);
4927                                 s390_l   (code, inst->dreg, 0, s390_r13, ainfo->offset);
4928                         } else
4929                                 g_assert_not_reached ();
4930
4931                         if (cfg->verbose_level > 2)
4932                                 g_print ("Argument %d assigned to register %s\n", 
4933                                          pos, mono_arch_regname (inst->dreg));
4934                 } else {
4935                         if (ainfo->regtype == RegTypeGeneral) {
4936                                 if (!((ainfo->reg >= 2) && (ainfo->reg <= 6)))
4937                                         g_assert_not_reached();
4938                                 switch (ainfo->size) {
4939                                 case 1:
4940                                         s390_stc (code, ainfo->reg, 0, inst->inst_basereg, inst->inst_offset);
4941                                         break;
4942                                 case 2:
4943                                         s390_sth (code, ainfo->reg, 0, inst->inst_basereg, inst->inst_offset);
4944                                         break;
4945                                 case 8:
4946                                         s390_stm (code, ainfo->reg, ainfo->reg + 1, 
4947                                                   inst->inst_basereg, inst->inst_offset);
4948                                         break;
4949                                 default:
4950                                         s390_st  (code, ainfo->reg, 0, inst->inst_basereg, inst->inst_offset);
4951                                 }
4952                         } else if (ainfo->regtype == RegTypeBase) {
4953                         } else if (ainfo->regtype == RegTypeFP) {
4954                                 if (ainfo->size == 8)
4955                                         s390_std (code, ainfo->reg, 0, inst->inst_basereg, inst->inst_offset);
4956                                 else if (ainfo->size == 4)
4957                                         s390_ste (code, ainfo->reg, 0, inst->inst_basereg, inst->inst_offset);
4958                                 else
4959                                         g_assert_not_reached ();
4960                         } else if (ainfo->regtype == RegTypeStructByVal) {
4961                                 int doffset = inst->inst_offset;
4962                                 int reg;
4963                                 if (ainfo->reg != STK_BASE)
4964                                         reg = ainfo->reg;
4965                                 else {
4966                                         reg = s390_r0;
4967                                         s390_lr  (code, s390_r13, STK_BASE);
4968                                         s390_ahi (code, s390_r13, alloc_size);
4969                                 }
4970                                 switch (ainfo->size) {
4971                                         case 1:
4972                                                 if (ainfo->reg == STK_BASE)
4973                                                         s390_ic  (code, reg, 0, s390_r13, ainfo->offset+3);
4974                                                 s390_stc (code, reg, 0, inst->inst_basereg, doffset);
4975                                                 break;
4976                                         case 2:
4977                                                 if (ainfo->reg == STK_BASE)
4978                                                         s390_lh  (code, reg, 0, s390_r13, ainfo->offset+2);
4979                                                 s390_sth (code, reg, 0, inst->inst_basereg, doffset);
4980                                                 break;
4981                                         case 4:
4982                                                 if (ainfo->reg == STK_BASE)
4983                                                         s390_l   (code, reg, 0, s390_r13, ainfo->offset);
4984                                                 s390_st  (code, reg, 0, inst->inst_basereg, doffset);
4985                                                 break;
4986                                         case 8:
4987                                                 if (ainfo->reg == STK_BASE)
4988                                                         s390_lm  (code, s390_r0, s390_r1, s390_r13, ainfo->offset);
4989                                                 s390_stm (code, reg, reg+1, inst->inst_basereg, doffset);
4990                                                 break;
4991                                 }
4992                         } else if (ainfo->regtype == RegTypeStructByAddr) {
4993                                 if (ainfo->reg == STK_BASE) {
4994                                         s390_lr  (code, s390_r13, ainfo->reg);
4995                                         s390_ahi (code, s390_r13, alloc_size);
4996                                         s390_l   (code, s390_r13, 0, s390_r13, 
4997                                                   ainfo->offparm + S390_MINIMAL_STACK_SIZE);
4998                                         code = emit_memcpy (code, abs(ainfo->vtsize), 
4999                                                             inst->inst_basereg, 
5000                                                             inst->inst_offset, s390_r13, 0);
5001                                 } else {
5002                                         code = emit_memcpy (code, abs(ainfo->vtsize), 
5003                                                             inst->inst_basereg, 
5004                                                             inst->inst_offset, 
5005                                                             ainfo->reg, 0);
5006                                 }
5007                         } else
5008                                 g_assert_not_reached ();
5009                 }
5010                 pos++;
5011         }
5012
5013         if (method->save_lmf) {
5014                 /*---------------------------------------------------------------*/
5015                 /* Preserve the parameter registers while we fix up the lmf      */
5016                 /*---------------------------------------------------------------*/
5017                 s390_lr (code, s390_r7, s390_r2);
5018                 s390_lr (code, s390_r8, s390_r3);
5019                 s390_lr (code, s390_r9, s390_r4);
5020                 s390_lr (code, s390_r10, s390_r5);
5021
5022                 mono_add_patch_info (cfg, code - cfg->native_code, 
5023                                      MONO_PATCH_INFO_INTERNAL_METHOD, 
5024                                      (gpointer)"mono_get_lmf_addr");
5025                 /*---------------------------------------------------------------*/
5026                 /* On return from this call r2 have the address of the &lmf      */
5027                 /*---------------------------------------------------------------*/
5028                 s390_brasl (code, s390_r14, 0);
5029
5030                 /*---------------------------------------------------------------*/
5031                 /* we build the MonoLMF structure on the stack - see mini-s390.h */
5032                 /*---------------------------------------------------------------*/
5033                 lmfOffset = alloc_size - sizeof(MonoLMF);       
5034                                                                                         
5035                 s390_lr    (code, s390_r13, cfg->frame_reg);            
5036                 s390_ahi   (code, s390_r13, lmfOffset);                                 
5037                                                                                         
5038                 /*---------------------------------------------------------------*/     
5039                 /* Set lmf.lmf_addr = jit_tls->lmf                               */     
5040                 /*---------------------------------------------------------------*/     
5041                 s390_st    (code, s390_r2, 0, s390_r13,                                 
5042                             G_STRUCT_OFFSET(MonoLMF, lmf_addr));                        
5043                                                                                         
5044                 /*---------------------------------------------------------------*/     
5045                 /* Get current lmf                                               */     
5046                 /*---------------------------------------------------------------*/     
5047                 s390_l     (code, s390_r0, 0, s390_r2, 0);                              
5048                                                                                         
5049                 /*---------------------------------------------------------------*/     
5050                 /* Set our lmf as the current lmf                                */     
5051                 /*---------------------------------------------------------------*/     
5052                 s390_st    (code, s390_r13, 0, s390_r2, 0);                             
5053                                                                                         
5054                 /*---------------------------------------------------------------*/     
5055                 /* Have our lmf.previous_lmf point to the last lmf               */     
5056                 /*---------------------------------------------------------------*/     
5057                 s390_st    (code, s390_r0, 0, s390_r13,                                 
5058                             G_STRUCT_OFFSET(MonoLMF, previous_lmf));                    
5059                                                                                         
5060                 /*---------------------------------------------------------------*/     
5061                 /* save method info                                              */     
5062                 /*---------------------------------------------------------------*/     
5063                 s390_basr  (code, s390_r1, 0);                                          
5064                 s390_j     (code, 4);                                                   
5065                 s390_word  (code, method);                                              
5066                 s390_l     (code, s390_r1, 0, s390_r1, 4);                      
5067                 s390_st    (code, s390_r1, 0, s390_r13,                                 
5068                             G_STRUCT_OFFSET(MonoLMF, method));                          
5069                                                                                 
5070                 /*---------------------------------------------------------------*/     
5071                 /* save the current IP                                           */     
5072                 /*---------------------------------------------------------------*/     
5073                 s390_lr    (code, s390_r1, cfg->frame_reg);
5074                 s390_st    (code, s390_r1, 0, s390_r13, G_STRUCT_OFFSET(MonoLMF, ebp)); 
5075                 s390_basr  (code, s390_r1, 0);
5076                 s390_la    (code, s390_r1, 0, s390_r1, 0);                              
5077                 s390_st    (code, s390_r1, 0, s390_r13, G_STRUCT_OFFSET(MonoLMF, eip)); 
5078                                                                                         
5079                 /*---------------------------------------------------------------*/     
5080                 /* Save general and floating point registers                     */     
5081                 /*---------------------------------------------------------------*/     
5082                 s390_stm   (code, s390_r2, s390_r12, s390_r13,                          
5083                             G_STRUCT_OFFSET(MonoLMF, gregs[2]));                        
5084                 for (i = 0; i < 16; i++) {                                              
5085                         s390_std  (code, i, 0, s390_r13,                                
5086                                    G_STRUCT_OFFSET(MonoLMF, fregs[i]));                 
5087                 }                                                                       
5088
5089                 /*---------------------------------------------------------------*/
5090                 /* Restore the parameter registers now that we've set up the lmf */
5091                 /*---------------------------------------------------------------*/
5092                 s390_lr (code, s390_r2, s390_r7);
5093                 s390_lr (code, s390_r3, s390_r8);
5094                 s390_lr (code, s390_r4, s390_r9);
5095                 s390_lr (code, s390_r5, s390_r10);
5096         }
5097
5098         if (tracing)
5099                 code = mono_arch_instrument_prolog (cfg, enter_method, code, TRUE);
5100
5101         cfg->code_len = code - cfg->native_code;
5102         g_free (cinfo);
5103
5104         return code;
5105 }
5106
5107 /*========================= End of Function ========================*/
5108
5109 /*------------------------------------------------------------------*/
5110 /*                                                                  */
5111 /* Name         - mono_arch_emit_epilog                             */
5112 /*                                                                  */
5113 /* Function     - Emit the instructions for a function epilog.      */
5114 /*                                                                  */
5115 /*------------------------------------------------------------------*/
5116
5117 void
5118 mono_arch_emit_epilog (MonoCompile *cfg)
5119 {
5120         MonoJumpInfo *patch_info;
5121         MonoMethod *method = cfg->method;
5122         int tracing = 0;
5123         guint8 *code;
5124         int max_epilog_size = 96;
5125         
5126         if (cfg->method->save_lmf)
5127                 max_epilog_size += 128;
5128         
5129         if (mono_jit_trace_calls != NULL)
5130                 max_epilog_size += 128;
5131
5132         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5133                 max_epilog_size += 128;
5134         
5135         while ((cfg->code_len + max_epilog_size) > (cfg->code_size - 16)) {
5136                 cfg->code_size  *= 2;
5137                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5138                 mono_jit_stats.code_reallocs++;
5139         }
5140
5141         code = cfg->native_code + cfg->code_len;
5142
5143         if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5144                 code = mono_arch_instrument_epilog (cfg, leave_method, code, TRUE);
5145                 tracing = 1;
5146         }
5147         
5148         if (method->save_lmf) 
5149                 restoreLMF(code, cfg->frame_reg, cfg->stack_usage);
5150
5151         if (cfg->flags & MONO_CFG_HAS_ALLOCA) 
5152                 s390_l   (code, STK_BASE, 0, STK_BASE, 0);
5153         else
5154                 code = backUpStackPtr(cfg, code);
5155
5156         s390_lm  (code, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
5157         s390_br  (code, s390_r14);
5158
5159         cfg->code_len = code - cfg->native_code;
5160
5161         g_assert (cfg->code_len < cfg->code_size);
5162
5163 }
5164
5165 /*========================= End of Function ========================*/
5166
5167 /*------------------------------------------------------------------*/
5168 /*                                                                  */
5169 /* Name         - mono_arch_emit_exceptions                         */
5170 /*                                                                  */
5171 /* Function     - Emit the blocks to handle exception conditions.   */
5172 /*                                                                  */
5173 /*------------------------------------------------------------------*/
5174
5175 void
5176 mono_arch_emit_exceptions (MonoCompile *cfg) 
5177 {
5178         MonoJumpInfo    *patch_info;
5179         guint8          *code;
5180         int             nThrows = 0,
5181                         exc_count = 0,
5182                         iExc;
5183         guint32         code_size;
5184         MonoClass       *exc_classes [MAX_EXC];
5185         guint8          *exc_throw_start [MAX_EXC], 
5186                         *exc_throw_end [MAX_EXC];
5187
5188         for (patch_info = cfg->patch_info; 
5189              patch_info; 
5190              patch_info = patch_info->next) {
5191                 if (patch_info->type == MONO_PATCH_INFO_EXC)
5192                         exc_count++;
5193         }
5194
5195         code_size = exc_count * 26;
5196
5197         while ((cfg->code_len + code_size) > (cfg->code_size - 16)) {
5198                 cfg->code_size  *= 2;
5199                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5200                 mono_jit_stats.code_reallocs++; 
5201         }
5202
5203         code = cfg->native_code + cfg->code_len;
5204
5205         /*---------------------------------------------------------------------*/
5206         /* Add code to raise exceptions                                        */
5207         /*---------------------------------------------------------------------*/
5208         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5209                 switch (patch_info->type) {
5210                 case MONO_PATCH_INFO_EXC: {
5211                         guint8 *ip = patch_info->ip.i + cfg->native_code;
5212                         MonoClass *exc_class;
5213                         guint32 throw_ip;
5214
5215                         /*-----------------------------------------------------*/
5216                         /* Patch the branch in epilog to come here             */
5217                         /*-----------------------------------------------------*/
5218                         s390_patch (ip + 2, S390_RELATIVE(code,ip));
5219
5220                         exc_class = mono_class_from_name (mono_defaults.corlib, 
5221                                                           "System", 
5222                                                           patch_info->data.name);
5223                         g_assert (exc_class);
5224                         throw_ip = patch_info->ip.i;
5225
5226                         for (iExc = 0; iExc < nThrows; ++iExc)
5227                                 if (exc_classes [iExc] == exc_class)
5228                                         break;
5229                 
5230                         if (iExc < nThrows) {
5231                                 s390_jcl (code, S390_CC_UN, exc_throw_start [iExc]);
5232                                 patch_info->type = MONO_PATCH_INFO_NONE;
5233                         } else {
5234         
5235                                 if (nThrows < MAX_EXC) {
5236                                         exc_classes [nThrows]     = exc_class;
5237                                         exc_throw_start [nThrows] = code;
5238                                 }
5239         
5240                                 /*---------------------------------------------*/
5241                                 /* Patch the parameter passed to the handler   */ 
5242                                 /*---------------------------------------------*/
5243                                 s390_basr (code, s390_r13, 0);
5244                                 s390_j    (code, 4);
5245                                 s390_word (code, patch_info->data.target);
5246                                 /*---------------------------------------------*/
5247                                 /* Load return address & parameter register    */
5248                                 /*---------------------------------------------*/
5249                                 s390_larl (code, s390_r14, S390_RELATIVE((patch_info->ip.i +
5250                                                            cfg->native_code + 8), code));
5251                                 s390_l    (code, s390_r2, 0, s390_r13, 4);
5252                                 /*---------------------------------------------*/
5253                                 /* Reuse the current patch to set the jump     */
5254                                 /*---------------------------------------------*/
5255                                 patch_info->type      = MONO_PATCH_INFO_INTERNAL_METHOD;
5256                                 patch_info->data.name = "mono_arch_throw_exception_by_name";
5257                                 patch_info->ip.i      = code - cfg->native_code;
5258                                 s390_jcl  (code, S390_CC_UN, 0);
5259                         }
5260                         break;
5261                 }
5262                 default:
5263                         /* do nothing */
5264                         break;
5265                 }
5266         }
5267
5268         cfg->code_len = code - cfg->native_code;
5269
5270         g_assert (cfg->code_len < cfg->code_size);
5271
5272 }
5273
5274 /*========================= End of Function ========================*/
5275
5276 /*------------------------------------------------------------------*/
5277 /*                                                                  */
5278 /* Name         - mono_arch_setup_jit_tls_data                      */
5279 /*                                                                  */
5280 /* Function     - Setup the JIT's Thread Level Specific Data.       */
5281 /*                                                                  */
5282 /*------------------------------------------------------------------*/
5283
5284 void
5285 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
5286 {
5287 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
5288         pthread_t       self = pthread_self();
5289         pthread_attr_t  attr;
5290         void            *stAddr = NULL;
5291         size_t          stSize  = 0;
5292         struct sigaltstack sa;
5293 #endif
5294
5295         if (!tls_offset_inited) {
5296                 tls_offset_inited = TRUE;
5297
5298 #if HAVE_KW_THREAD
5299 # if 0
5300         __asm__ ("\tear\t%r1,0\n"
5301                  "\tlr\t%0,%3\n"
5302                  "\tsr\t%0,%r1\n"
5303                  "\tlr\t%1,%4\n"
5304                  "\tsr\t%1,%r1\n"
5305                  "\tlr\t%2,%5\n"
5306                  "\tsr\t%2,%r1\n"
5307                  : "=r" (appdomain_tls_offset),
5308                    "=r" (thread_tls_offset),
5309                    "=r" (lmf_tls_offset)
5310                  : "r" (&tls_appdomain),
5311                    "r" (&tls_current_object),
5312                    "r" (&mono_lmf_addr)
5313                  : "1", "cc");
5314 # endif
5315 #endif
5316         }               
5317
5318 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
5319
5320         /*----------------------------------------------------------*/
5321         /* Determine stack boundaries                               */
5322         /*----------------------------------------------------------*/
5323         if (!mono_running_on_valgrind ()) {
5324 #ifdef HAVE_PTHREAD_GETATTR_NP
5325                 pthread_getattr_np( self, &attr );
5326 #elif HAVE_PTHREAD_ATTR_GET_NP
5327                 pthread_attr_get_np( self, &attr );
5328 #endif
5329                 pthread_attr_getstack( &attr, &stAddr, &stSize );
5330         }
5331
5332
5333         /*----------------------------------------------------------*/
5334         /* Setup an alternate signal stack                          */
5335         /*----------------------------------------------------------*/
5336         tls->stack_size        = stSize;
5337         tls->signal_stack      = g_malloc (SIGNAL_STACK_SIZE);
5338         tls->signal_stack_size = SIGNAL_STACK_SIZE;
5339
5340         sa.ss_sp    = tls->signal_stack;
5341         sa.ss_size  = SIGNAL_STACK_SIZE;
5342         sa.ss_flags = SS_ONSTACK;
5343         sigaltstack (&sa, NULL);
5344 #endif
5345
5346 }
5347
5348 /*========================= End of Function ========================*/
5349
5350 /*------------------------------------------------------------------*/
5351 /*                                                                  */
5352 /* Name         - mono_arch_free_jit_tls_data                       */
5353 /*                                                                  */
5354 /* Function     - Free tls data.                                    */
5355 /*                                                                  */
5356 /*------------------------------------------------------------------*/
5357
5358 void
5359 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5360 {
5361 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
5362         struct sigaltstack sa;
5363
5364         sa.ss_sp    = tls->signal_stack;
5365         sa.ss_size  = SIGNAL_STACK_SIZE;
5366         sa.ss_flags = SS_DISABLE;
5367         sigaltstack (&sa, NULL);
5368
5369         if (tls->signal_stack)
5370                 g_free (tls->signal_stack);
5371 #endif
5372
5373 }
5374
5375 /*========================= End of Function ========================*/
5376
5377 /*------------------------------------------------------------------*/
5378 /*                                                                  */
5379 /* Name         - mono_arch_emit_this_vret_args                     */
5380 /*                                                                  */
5381 /* Function     -                                                   */
5382 /*                                                                  */
5383 /*------------------------------------------------------------------*/
5384
5385 void
5386 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
5387 {
5388         int this_dreg = s390_r2;
5389         
5390         if (vt_reg != -1)
5391                 this_dreg = s390_r3;
5392
5393         /* add the this argument */
5394         if (this_reg != -1) {
5395                 MonoInst *this;
5396                 MONO_INST_NEW (cfg, this, OP_SETREG);
5397                 this->type = this_type;
5398                 this->sreg1 = this_reg;
5399                 this->dreg = this_dreg;
5400                 mono_bblock_add_inst (cfg->cbb, this);
5401         }
5402
5403         if (vt_reg != -1) {
5404                 MonoInst *vtarg;
5405                 MONO_INST_NEW (cfg, vtarg, OP_SETREG);
5406                 vtarg->type = STACK_MP;
5407                 vtarg->sreg1 = vt_reg;
5408                 vtarg->dreg = s390_r2;
5409                 mono_bblock_add_inst (cfg->cbb, vtarg);
5410         }
5411 }
5412
5413 /*========================= End of Function ========================*/
5414
5415 /*------------------------------------------------------------------*/
5416 /*                                                                  */
5417 /* Name         - mono_arch_get_inst_for_method                   */
5418 /*                                                                  */
5419 /* Function     - Check for opcodes we can handle directly in       */
5420 /*                hardware.                                         */
5421 /*                                                                  */
5422 /*------------------------------------------------------------------*/
5423
5424 MonoInst*
5425 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, 
5426                                MonoMethodSignature *fsig, MonoInst **args)
5427 {
5428         MonoInst *ins = NULL;
5429
5430         if (cmethod->klass == mono_defaults.math_class) {
5431                 if (strcmp (cmethod->name, "Sqrt") == 0) {
5432                         MONO_INST_NEW (cfg, ins, OP_SQRT);
5433                         ins->inst_i0 = args [0];
5434                 }
5435         } else if(cmethod->klass->image == mono_defaults.corlib &&
5436                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
5437                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
5438
5439                 if (strcmp (cmethod->name, "Increment") == 0 && 
5440                     fsig->params [0]->type == MONO_TYPE_I4) {
5441                         MonoInst *ins_iconst;
5442
5443                         MONO_INST_NEW (cfg, ins, OP_ATOMIC_ADD_NEW_I4);
5444                         MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
5445                         ins_iconst->inst_c0 = 1;
5446
5447                         ins->inst_i0 = args [0];
5448                         ins->inst_i1 = ins_iconst;
5449                 } else if (strcmp (cmethod->name, "Decrement") == 0 && 
5450                            fsig->params [0]->type == MONO_TYPE_I4) {
5451                         MonoInst *ins_iconst;
5452
5453                         MONO_INST_NEW (cfg, ins, OP_ATOMIC_ADD_NEW_I4);
5454                         MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
5455                         ins_iconst->inst_c0 = -1;
5456
5457                         ins->inst_i0 = args [0];
5458                         ins->inst_i1 = ins_iconst;
5459                 } else if (strcmp (cmethod->name, "Exchange") == 0 && 
5460                            fsig->params [0]->type == MONO_TYPE_I4) {
5461                         MONO_INST_NEW (cfg, ins, OP_ATOMIC_EXCHANGE_I4);
5462
5463                         ins->inst_i0 = args [0];
5464                         ins->inst_i1 = args [1];
5465                 } else if (strcmp (cmethod->name, "Add") == 0 && 
5466                            fsig->params [0]->type == MONO_TYPE_I4) {
5467                         MONO_INST_NEW (cfg, ins, OP_ATOMIC_ADD_I4);
5468
5469                         ins->inst_i0 = args [0];
5470                         ins->inst_i1 = args [1];
5471                 }
5472         }
5473         return ins;
5474 }
5475
5476 /*========================= End of Function ========================*/
5477
5478 /*------------------------------------------------------------------*/
5479 /*                                                                  */
5480 /* Name         - mono_arch_print_tree                              */
5481 /*                                                                  */
5482 /* Function     - Print platform-specific opcode details.           */
5483 /*                                                                  */
5484 /* Returns      - 1 - opcode details have been printed              */
5485 /*                0 - opcode details have not been printed          */
5486 /*                                                                  */
5487 /*------------------------------------------------------------------*/
5488
5489 gboolean
5490 mono_arch_print_tree (MonoInst *tree, int arity)
5491 {
5492         gboolean done;
5493
5494         switch (tree->opcode) {
5495                 case OP_S390_LOADARG:
5496                 case OP_S390_ARGPTR:
5497                         printf ("[0x%x(%s)]", tree->inst_offset, 
5498                                 mono_arch_regname (tree->inst_basereg));
5499                         done = 1;
5500                         break;
5501                 case OP_S390_STKARG:
5502                         printf ("[0x%x(previous_frame)]", 
5503                                 tree->inst_offset); 
5504                         done = 1;
5505                         break;
5506                 case OP_S390_MOVE:
5507                         printf ("[0x%x(%d,%s),0x%x(%s)]",
5508                                 tree->inst_offset, tree->unused,
5509                                 tree->dreg, tree->inst_imm, 
5510                                 tree->sreg1);
5511                         done = 1;
5512                         break;
5513                 case OP_S390_SETF4RET:
5514                         printf ("[f%d,f%d]", 
5515                                 mono_arch_regname (tree->dreg),
5516                                 mono_arch_regname (tree->sreg1));
5517                         done = 1;
5518                         break;
5519                 case OP_TLS_GET:
5520                         printf ("[0x%x(0x%x,%s)]", tree->inst_offset,
5521                                 tree->inst_imm,
5522                                 mono_arch_regname (tree->sreg1));
5523                         done = 1;
5524                 default:
5525                         done = 0;
5526         }
5527         return (done);
5528 }
5529
5530 /*========================= End of Function ========================*/
5531
5532 /*------------------------------------------------------------------*/
5533 /*                                                                  */
5534 /* Name         - mono_arch_regalloc_cost                           */
5535 /*                                                                  */
5536 /* Function     - Determine the cost, in the number of memory       */
5537 /*                references, of the action of allocating the var-  */
5538 /*                iable VMV into a register during global register  */
5539 /*                allocation.                                       */
5540 /*                                                                  */
5541 /* Returns      - Cost                                              */
5542 /*                                                                  */
5543 /*------------------------------------------------------------------*/
5544
5545 guint32
5546 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
5547 {
5548         /* FIXME: */
5549         return 2;
5550 }
5551
5552 /*========================= End of Function ========================*/
5553
5554 /*------------------------------------------------------------------*/
5555 /*                                                                  */
5556 /* Name         - mono_arch_get_domain_intrinsic                    */
5557 /*                                                                  */
5558 /* Function     -                                                   */
5559 /*                                                                  */
5560 /* Returns      -                                                   */
5561 /*                                                                  */
5562 /*------------------------------------------------------------------*/
5563
5564 MonoInst * 
5565 mono_arch_get_domain_intrinsic (MonoCompile* cfg)
5566 {
5567         MonoInst *ins;
5568
5569         if (appdomain_tls_offset == -1)
5570                 return NULL;
5571         
5572         MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5573         ins->inst_offset = appdomain_tls_offset;
5574         return (ins);
5575 }
5576
5577 /*========================= End of Function ========================*/
5578
5579 /*------------------------------------------------------------------*/
5580 /*                                                                  */
5581 /* Name         - mono_arch_get_thread_intrinsic                    */
5582 /*                                                                  */
5583 /* Function     -                                                   */
5584 /*                                                                  */
5585 /* Returns      -                                                   */
5586 /*                                                                  */
5587 /*------------------------------------------------------------------*/
5588
5589 MonoInst * 
5590 mono_arch_get_thread_intrinsic (MonoCompile* cfg)
5591 {
5592         MonoInst *ins;
5593
5594         if (thread_tls_offset == -1)
5595                 return NULL;
5596         
5597         MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5598         ins->inst_offset = thread_tls_offset;
5599         return (ins);
5600 }
5601
5602 /*========================= End of Function ========================*/
5603
5604 /*------------------------------------------------------------------*/
5605 /*                                                                  */
5606 /* Name         - mono_arch_flush_register_windows                  */
5607 /*                                                                  */
5608 /* Function     -                                                   */
5609 /*                                                                  */
5610 /* Returns      -                                                   */
5611 /*                                                                  */
5612 /*------------------------------------------------------------------*/
5613
5614 void 
5615 mono_arch_flush_register_windows (void)
5616 {
5617 }
5618
5619 /*========================= End of Function ========================*/