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