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