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