1 /*------------------------------------------------------------------*/
3 /* Name - mini-s390.c */
5 /* Function - S/390 backend for the Mono code generator. */
7 /* Name - Neale Ferguson (Neale.Ferguson@SoftwareAG-usa.com) */
9 /* Date - January, 2004 */
11 /* Derivation - From mini-x86 & mini-ppc by - */
12 /* Paolo Molaro (lupus@ximian.com) */
13 /* Dietmar Maurer (dietmar@ximian.com) */
15 /*------------------------------------------------------------------*/
17 /*------------------------------------------------------------------*/
19 /*------------------------------------------------------------------*/
21 #define NOT_IMPLEMENTED(x) \
22 g_error ("FIXME: %s is not yet implemented. (trampoline)", x);
24 #define EMIT_COND_BRANCH(ins,cond) \
25 if (ins->flags & MONO_INST_BRLABEL) { \
26 if (ins->inst_i0->inst_c0) { \
28 displace = ((cfg->native_code + ins->inst_i0->inst_c0) - code) / 2; \
29 if (s390_is_uimm16(displace)) { \
30 s390_brc (code, cond, displace); \
32 s390_jcl (code, cond, displace); \
35 mono_add_patch_info (cfg, code - cfg->native_code, \
36 MONO_PATCH_INFO_LABEL, ins->inst_i0); \
37 s390_jcl (code, cond, 0); \
40 if (ins->inst_true_bb->native_offset) { \
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); \
47 s390_jcl (code, cond, displace); \
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); \
56 #define EMIT_UNCOND_BRANCH(ins) \
57 if (ins->flags & MONO_INST_BRLABEL) { \
58 if (ins->inst_i0->inst_c0) { \
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); \
64 s390_jcl (code, S390_CC_UN, displace); \
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); \
72 if (ins->inst_target_bb->native_offset) { \
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); \
79 s390_jcl (code, S390_CC_UN, displace); \
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); \
88 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) \
90 mono_add_patch_info (cfg, code - cfg->native_code, \
91 MONO_PATCH_INFO_EXC, exc_name); \
92 s390_jcl (code, cond, 0); \
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)
100 /*----------------------------------------*/
101 /* use s390_r3-s390_r10 as temp registers */
102 /*----------------------------------------*/
103 #define S390_CALLER_REGS (0x03f8)
105 /*----------------------------------------*/
106 /* use s390_f2-s390_f14 as temp registers */
107 /*----------------------------------------*/
108 #define S390_CALLER_FREGS (0x73f8)
110 #define S390_TRACE_STACK_SIZE (5*sizeof(gint32)+3*sizeof(gdouble))
112 /*========================= End of Defines =========================*/
114 /*------------------------------------------------------------------*/
115 /* I n c l u d e s */
116 /*------------------------------------------------------------------*/
121 #include <mono/metadata/appdomain.h>
122 #include <mono/metadata/debug-helpers.h>
124 #include "mini-s390.h"
126 #include "cpu-s390.h"
128 /*========================= End of Includes ========================*/
130 /*------------------------------------------------------------------*/
131 /* T y p e d e f s */
132 /*------------------------------------------------------------------*/
141 /*------------------------------------------------------------------*/
142 /* Used by the instrument_emit_epilog */
143 /*------------------------------------------------------------------*/
160 typedef struct InstList InstList
;
177 gint32 offset
; /* offset from caller's stack */
178 gint32 offparm
; /* offset on callee's stack */
179 guint16 vtsize
; /* in param area */
181 guint8 regtype
; /* See RegType* */
182 guint32 size
; /* Size of structure used by RegTypeStructByVal */
194 gint32 gr
[5]; /* R2-R6 */
195 gdouble fp
[3]; /* F0-F2 */
196 } __attribute__ ((packed
)) RegParm
;
198 /*========================= End of Typedefs ========================*/
200 /*------------------------------------------------------------------*/
201 /* P r o t o t y p e s */
202 /*------------------------------------------------------------------*/
204 static guint32
*emit_memcpy (guint8
*, int, int, int, int, int);
205 static void indent (int);
206 static void decodeParm (MonoType
*, void *, int);
207 static void enter_method (MonoMethod
*, RegParm
*, char *);
208 static void leave_method (MonoMethod
*, ...);
209 static gboolean
is_regsize_var (MonoType
*);
210 static void add_general (guint
*, size_data
*, ArgInfo
*, gboolean
);
211 static CallInfo
* calculate_sizes (MonoMethodSignature
*, size_data
*, gboolean
);
212 static void peephole_pass (MonoCompile
*, MonoBasicBlock
*);
213 static int mono_spillvar_offset (MonoCompile
*, int);
214 static int mono_spillvar_offset_float (MonoCompile
*, int);
215 static void print_ins (int, MonoInst
*);
216 static void print_regtrack (RegTrack
*, int);
217 static InstList
* inst_list_prepend (MonoMemPool
*, InstList
*, MonoInst
*);
218 static int get_register_force_spilling (MonoCompile
*, InstList
*, MonoInst
*, int);
219 static int get_register_spilling (MonoCompile
*, InstList
*, MonoInst
*, guint32
, int);
220 static int get_float_register_spilling (MonoCompile
*, InstList
*, MonoInst
*, guint32
, int);
221 static MonoInst
* create_copy_ins (MonoCompile
*, int, int, MonoInst
*);
222 static MonoInst
* create_copy_ins_float (MonoCompile
*, int, int, MonoInst
*);
223 static MonoInst
* create_spilled_store (MonoCompile
*, int, int, int, MonoInst
*);
224 static MonoInst
* create_spilled_store_float (MonoCompile
*, int, int, int, MonoInst
*);
225 static void insert_before_ins (MonoInst
*, InstList
*, MonoInst
*);
226 static int alloc_int_reg (MonoCompile
*, InstList
*, MonoInst
*, int, guint32
);
227 static guchar
* emit_float_to_int (MonoCompile
*, guchar
*, int, int, int, gboolean
);
228 static unsigned char * mono_emit_stack_alloc (guchar
*, MonoInst
*);
230 /*========================= End of Prototypes ======================*/
232 /*------------------------------------------------------------------*/
233 /* G l o b a l V a r i a b l e s */
234 /*------------------------------------------------------------------*/
236 int mono_exc_esp_offset
= 0;
238 static int indent_level
= 0;
240 static const char*const * ins_spec
= s390
;
242 /*====================== End of Global Variables ===================*/
244 /*------------------------------------------------------------------*/
246 /* Name - mono_arch_regname */
248 /* Function - Returns the name of the register specified by */
249 /* the input parameter. */
251 /*------------------------------------------------------------------*/
254 mono_arch_regname (int reg
) {
255 static const char * rnames
[] = {
256 "s390_r0", "s390_sp", "s390_r2", "s390_r3", "s390_r4",
257 "s390_r5", "s390_r6", "s390_r7", "s390_r8", "s390_r9",
258 "s390_r10", "s390_r11", "s390_r12", "s390_r13", "s390_r14",
261 if (reg
>= 0 && reg
< 16)
266 /*========================= End of Function ========================*/
268 /*------------------------------------------------------------------*/
270 /* Name - emit_memcpy */
272 /* Function - Emit code to move from memory-to-memory based on */
273 /* the size of the variable. r0 is overwritten. */
275 /*------------------------------------------------------------------*/
278 emit_memcpy (guint8
*code
, int size
, int dreg
, int doffset
, int sreg
, int soffset
)
282 s390_l (code
, s390_r0
, 0, sreg
, soffset
);
283 s390_st (code
, s390_r0
, 0, dreg
, doffset
);
287 s390_icm (code
, s390_r0
, 14, sreg
, soffset
);
288 s390_stcm (code
, s390_r0
, 14, dreg
, doffset
);
292 s390_lh (code
, s390_r0
, 0, sreg
, soffset
);
293 s390_sth (code
, s390_r0
, 0, dreg
, doffset
);
297 s390_ic (code
, s390_r0
, 0, sreg
, soffset
);
298 s390_stc (code
, s390_r0
, 0, dreg
, doffset
);
309 s390_mvc (code
, len
, dreg
, doffset
, sreg
, soffset
);
316 /*========================= End of Function ========================*/
318 /*------------------------------------------------------------------*/
320 /* Name - arch_get_argument_info */
322 /* Function - Gathers information on parameters such as size, */
323 /* alignment, and padding. arg_info should be large */
324 /* enough to hold param_count + 1 entries. */
326 /* Parameters - @csig - Method signature */
327 /* @param_count - No. of parameters to consider */
328 /* @arg_info - An array to store the result info */
330 /* Returns - Size of the activation frame */
332 /*------------------------------------------------------------------*/
335 mono_arch_get_argument_info (MonoMethodSignature
*csig
,
337 MonoJitArgumentInfo
*arg_info
)
339 int k
, frame_size
= 0;
340 int size
, align
, pad
;
343 if (MONO_TYPE_ISSTRUCT (csig
->ret
)) {
344 frame_size
+= sizeof (gpointer
);
348 arg_info
[0].offset
= offset
;
351 frame_size
+= sizeof (gpointer
);
355 arg_info
[0].size
= frame_size
;
357 for (k
= 0; k
< param_count
; k
++) {
360 size
= mono_type_native_stack_size (csig
->params
[k
], &align
);
362 size
= mono_type_stack_size (csig
->params
[k
], &align
);
364 frame_size
+= pad
= (align
- (frame_size
& (align
- 1))) & (align
- 1);
365 arg_info
[k
].pad
= pad
;
367 arg_info
[k
+ 1].pad
= 0;
368 arg_info
[k
+ 1].size
= size
;
370 arg_info
[k
+ 1].offset
= offset
;
374 align
= MONO_ARCH_FRAME_ALIGNMENT
;
375 frame_size
+= pad
= (align
- (frame_size
& (align
- 1))) & (align
- 1);
376 arg_info
[k
].pad
= pad
;
381 /*========================= End of Function ========================*/
383 /*------------------------------------------------------------------*/
387 /* Function - Perform nice indenting to current level */
389 /*------------------------------------------------------------------*/
395 indent_level
+= diff
;
402 indent_level
+= diff
;
405 /*========================= End of Function ========================*/
407 /*------------------------------------------------------------------*/
409 /* Name - decodeParm */
411 /* Function - Decode a parameter for the trace. */
413 /*------------------------------------------------------------------*/
416 decodeParm(MonoType
*type
, void *curParm
, int size
)
421 printf("[BYREF:%p], ", *((char **) curParm
));
423 simpleType
= type
->type
;
425 switch (simpleType
) {
427 printf ("[INTPTR:%p], ", *((int **) curParm
));
430 printf ("[UINTPTR:%p], ", *((int **) curParm
));
432 case MONO_TYPE_BOOLEAN
:
433 printf ("[BOOL:%p], ", *((int *) curParm
));
435 case MONO_TYPE_CHAR
:
436 printf ("[CHAR:%p], ", *((int *) curParm
));
439 printf ("[INT1:%d], ", *((int *) curParm
+3));
442 printf ("[INT2:%d], ", *((int *) curParm
+2));
445 printf ("[INT4:%d], ", *((int *) curParm
));
448 printf ("[UINT1:%ud], ", *((unsigned int *) curParm
));
451 printf ("[UINT2:%ud], ", *((unsigned int *) curParm
));
454 printf ("[UINT4:%ud], ", *((unsigned int *) curParm
));
456 case MONO_TYPE_STRING
: {
457 MonoString
*s
= *((MonoString
**) curParm
);
459 g_assert (((MonoObject
*) s
)->vtable
->klass
== mono_defaults
.string_class
);
460 printf("[STRING:%p:%s], ", s
, mono_string_to_utf8(s
));
462 printf("[STRING:null], ");
466 case MONO_TYPE_CLASS
:
467 case MONO_TYPE_OBJECT
: {
468 MonoObject
*obj
= *((MonoObject
**) curParm
);
471 printf("[CLASS/OBJ:");
472 class = obj
->vtable
->klass
;
473 if (class == mono_defaults
.string_class
) {
474 printf("[STRING:%p:%s]",
475 *obj
, mono_string_to_utf8 (obj
));
476 } else if (class == mono_defaults
.int32_class
) {
477 printf("[INT32:%p:%d]",
478 obj
, *(gint32
*)((char *)obj
+ sizeof (MonoObject
)));
481 class->name_space
, class->name
, obj
);
484 printf("[OBJECT:null], ");
489 printf("[PTR:%p], ", *((gpointer
**) (curParm
)));
491 case MONO_TYPE_FNPTR
:
492 printf("[FNPTR:%p], ", *((gpointer
**) (curParm
)));
494 case MONO_TYPE_ARRAY
:
495 printf("[ARRAY:%p], ", *((gpointer
**) (curParm
)));
497 case MONO_TYPE_SZARRAY
:
498 printf("[SZARRAY:%p], ", *((gpointer
**) (curParm
)));
501 printf("[INT8:%lld], ", *((gint64
*) (curParm
)));
504 printf("[FLOAT4:%f], ", *((float *) (curParm
)));
507 printf("[FLOAT8:%g], ", *((double *) (curParm
)));
509 case MONO_TYPE_VALUETYPE
: {
511 if (type
->data
.klass
->enumtype
) {
512 simpleType
= type
->data
.klass
->enum_basetype
->type
;
513 printf("{VALUETYPE} - ");
516 printf("[VALUETYPE:");
517 for (i
= 0; i
< size
; i
++)
518 printf("%02x,", *((guint8
*)curParm
+i
));
523 printf("[?? - %d], ",simpleType
);
528 /*========================= End of Function ========================*/
530 /*------------------------------------------------------------------*/
532 /* Name - enter_method */
534 /* Function - Perform tracing of the entry to the current */
537 /*------------------------------------------------------------------*/
540 enter_method (MonoMethod
*method
, RegParm
*rParm
, char *sp
)
545 MonoJitArgumentInfo
*arg_info
;
546 MonoMethodSignature
*sig
;
552 fname
= mono_method_full_name (method
, TRUE
);
554 printf ("ENTER: %s(", fname
);
557 printf (") ip: %p sp: %p\n", __builtin_return_address (1), sp
);
562 sig
= method
->signature
;
564 cinfo
= calculate_sizes (sig
, &sz
, sig
->pinvoke
);
566 if (cinfo
->struct_ret
) {
567 printf ("[VALUERET:%p], ", rParm
->gr
[0]);
572 gpointer
*this = (gpointer
*) rParm
->gr
[oParm
];
573 obj
= (MonoObject
*) this;
574 if (method
->klass
->valuetype
) {
576 printf("this:[value:%p:%08x], ",
577 this, *((guint32
*)(this+sizeof(MonoObject
))));
579 printf ("this:[NULL], ");
582 class = obj
->vtable
->klass
;
583 if (class == mono_defaults
.string_class
) {
584 printf ("this:[STRING:%p:%s], ",
585 obj
, mono_string_to_utf8 ((MonoString
*)obj
));
587 printf ("this:%p[%s.%s], ",
588 obj
, class->name_space
, class->name
);
591 printf ("this:NULL, ");
596 for (i
= 0; i
< sig
->param_count
; ++i
) {
597 ainfo
= cinfo
->args
+ i
+ oParm
;
598 switch (ainfo
->regtype
) {
599 case RegTypeGeneral
:
600 decodeParm(sig
->params
[i
], &(rParm
->gr
[ainfo
->reg
-2]), ainfo
->size
);
603 decodeParm(sig
->params
[i
], &(rParm
->fp
[ainfo
->reg
]), ainfo
->size
);
606 decodeParm(sig
->params
[i
], sp
+ainfo
->offset
, ainfo
->size
);
608 case RegTypeStructByVal
:
609 if (ainfo
->reg
!= STK_BASE
)
610 decodeParm(sig
->params
[i
],
611 &(rParm
->gr
[ainfo
->reg
-2]),
614 switch (ainfo
->vtsize
) {
620 decodeParm(sig
->params
[i
],
625 decodeParm(sig
->params
[i
],
626 *((char **) (sp
+ainfo
->offset
)),
638 /*========================= End of Function ========================*/
640 /*------------------------------------------------------------------*/
642 /* Name - leave_method */
646 /*------------------------------------------------------------------*/
649 leave_method (MonoMethod
*method
, ...)
655 va_start(ap
, method
);
657 fname
= mono_method_full_name (method
, TRUE
);
659 printf ("LEAVE: %s", fname
);
662 type
= method
->signature
->ret
;
665 switch (type
->type
) {
668 case MONO_TYPE_BOOLEAN
: {
669 int val
= va_arg (ap
, int);
671 printf ("[TRUE:%d]", val
);
677 case MONO_TYPE_CHAR
: {
678 int val
= va_arg (ap
, int);
679 printf ("[CHAR:%d]", val
);
683 int val
= va_arg (ap
, int);
684 printf ("[INT1:%d]", val
);
688 int val
= va_arg (ap
, int);
689 printf ("[UINT1:%d]", val
);
693 int val
= va_arg (ap
, int);
694 printf ("[INT2:%d]", val
);
698 int val
= va_arg (ap
, int);
699 printf ("[UINT2:%d]", val
);
703 int val
= va_arg (ap
, int);
704 printf ("[INT4:%d]", val
);
708 int val
= va_arg (ap
, int);
709 printf ("[UINT4:%d]", val
);
713 int *val
= va_arg (ap
, int*);
714 printf ("[INT:%p]", val
);
719 int *val
= va_arg (ap
, int*);
720 printf ("[UINT:%p]", val
);
724 case MONO_TYPE_STRING
: {
725 MonoString
*s
= va_arg (ap
, MonoString
*);
728 g_assert (((MonoObject
*)s
)->vtable
->klass
== mono_defaults
.string_class
);
729 printf ("[STRING:%p:%s]", s
, mono_string_to_utf8 (s
));
731 printf ("[STRING:null], ");
734 case MONO_TYPE_CLASS
:
735 case MONO_TYPE_OBJECT
: {
736 MonoObject
*o
= va_arg (ap
, MonoObject
*);
739 if (o
->vtable
->klass
== mono_defaults
.boolean_class
) {
740 printf ("[BOOLEAN:%p:%d]", o
, *((guint8
*)o
+ sizeof (MonoObject
)));
741 } else if (o
->vtable
->klass
== mono_defaults
.int32_class
) {
742 printf ("[INT32:%p:%d]", o
, *((gint32
*)((char *)o
+ sizeof (MonoObject
))));
743 } else if (o
->vtable
->klass
== mono_defaults
.int64_class
) {
744 printf ("[INT64:%p:%lld]", o
, *((gint64
*)((char *)o
+ sizeof (MonoObject
))));
746 printf ("[%s.%s:%p]", o
->vtable
->klass
->name_space
, o
->vtable
->klass
->name
, o
);
748 printf ("[OBJECT:%p]", o
);
753 case MONO_TYPE_FNPTR
:
754 case MONO_TYPE_ARRAY
:
755 case MONO_TYPE_SZARRAY
: {
756 gpointer p
= va_arg (ap
, gpointer
);
757 printf ("[result=%p]", p
);
761 gint64 l
= va_arg (ap
, gint64
);
762 printf ("[LONG:%lld]", l
);
766 double f
= va_arg (ap
, double);
767 printf ("[FP:%g]\n", f
);
770 case MONO_TYPE_VALUETYPE
:
771 if (type
->data
.klass
->enumtype
) {
772 type
= type
->data
.klass
->enum_basetype
;
775 guint8
*p
= va_arg (ap
, gpointer
);
777 size
= mono_type_size (type
, &align
);
779 for (j
= 0; p
&& j
< size
; j
++)
780 printf ("%02x,", p
[j
]);
785 printf ("(unknown return type %x)", method
->signature
->ret
->type
);
788 printf (" ip: %p\n", __builtin_return_address (0));
791 /*========================= End of Function ========================*/
793 /*------------------------------------------------------------------*/
795 /* Name - mono_arch_cpu_init */
797 /* Function - Perform CPU specific initialization to execute */
800 /*------------------------------------------------------------------*/
803 mono_arch_cpu_init (void)
807 /*========================= End of Function ========================*/
809 /*------------------------------------------------------------------*/
811 /* Name - mono_arch_cpu_optimizazions */
813 /* Function - Returns the optimizations supported on this CPU */
815 /*------------------------------------------------------------------*/
818 mono_arch_cpu_optimizazions (guint32
*exclude_mask
)
822 /* no s390-specific optimizations yet */
823 *exclude_mask
= MONO_OPT_INLINE
|MONO_OPT_LINEARS
;
827 /*========================= End of Function ========================*/
829 /*------------------------------------------------------------------*/
835 /*------------------------------------------------------------------*/
838 is_regsize_var (MonoType
*t
) {
847 case MONO_TYPE_OBJECT
:
848 case MONO_TYPE_STRING
:
849 case MONO_TYPE_CLASS
:
850 case MONO_TYPE_SZARRAY
:
851 case MONO_TYPE_ARRAY
:
853 case MONO_TYPE_VALUETYPE
:
854 if (t
->data
.klass
->enumtype
)
855 return is_regsize_var (t
->data
.klass
->enum_basetype
);
861 /*========================= End of Function ========================*/
863 /*------------------------------------------------------------------*/
865 /* Name - mono_arch_get_allocatable_int_vars */
869 /*------------------------------------------------------------------*/
872 mono_arch_get_allocatable_int_vars (MonoCompile
*cfg
)
877 for (i
= 0; i
< cfg
->num_varinfo
; i
++) {
878 MonoInst
*ins
= cfg
->varinfo
[i
];
879 MonoMethodVar
*vmv
= MONO_VARINFO (cfg
, i
);
882 if (vmv
->range
.first_use
.abs_pos
> vmv
->range
.last_use
.abs_pos
)
885 if (ins
->flags
& (MONO_INST_VOLATILE
|MONO_INST_INDIRECT
) || (ins
->opcode
!= OP_LOCAL
&& ins
->opcode
!= OP_ARG
))
888 /* we can only allocate 32 bit values */
889 if (is_regsize_var (ins
->inst_vtype
)) {
890 g_assert (MONO_VARINFO (cfg
, i
)->reg
== -1);
891 g_assert (i
== vmv
->idx
);
892 vars
= mono_varlist_insert_sorted (cfg
, vars
, vmv
, FALSE
);
899 /*========================= End of Function ========================*/
901 /*------------------------------------------------------------------*/
903 /* Name - mono_arch_global_int_regs */
905 /* Function - Return a list of usable integer registers. */
907 /*------------------------------------------------------------------*/
910 mono_arch_get_global_int_regs (MonoCompile
*cfg
)
915 for (i
= 3; i
< top
; ++i
)
916 regs
= g_list_prepend (regs
, GUINT_TO_POINTER (i
));
921 /*========================= End of Function ========================*/
923 /*------------------------------------------------------------------*/
925 /* Name - mono_arch_flush_icache */
927 /* Function - Flush the CPU icache. */
929 /*------------------------------------------------------------------*/
932 mono_arch_flush_icache (guint8
*code
, gint size
)
936 /*========================= End of Function ========================*/
938 /*------------------------------------------------------------------*/
940 /* Name - add_general */
942 /* Function - Determine code and stack size incremements for a */
945 /*------------------------------------------------------------------*/
948 add_general (guint
*gr
, size_data
*sz
, ArgInfo
*ainfo
, gboolean simple
)
951 if (*gr
> S390_LAST_ARG_REG
) {
952 sz
->stack_size
= S390_ALIGN(sz
->stack_size
, sizeof(long));
953 ainfo
->offset
= sz
->stack_size
;
954 ainfo
->reg
= STK_BASE
;
955 ainfo
->regtype
= RegTypeBase
;
956 sz
->stack_size
+= sizeof(int);
963 if (*gr
> S390_LAST_ARG_REG
- 1) {
964 sz
->stack_size
= S390_ALIGN(sz
->stack_size
, S390_STACK_ALIGNMENT
);
965 ainfo
->offset
= sz
->stack_size
;
966 ainfo
->reg
= STK_BASE
;
967 ainfo
->regtype
= RegTypeBase
;
968 sz
->stack_size
+= sizeof(long long);
979 /*========================= End of Function ========================*/
981 /*------------------------------------------------------------------*/
983 /* Name - calculate_sizes */
985 /* Function - Determine the amount of space required for code */
986 /* and stack. In addition determine starting points */
987 /* for stack-based parameters, and area for struct- */
988 /* ures being returned on the stack. */
990 /*------------------------------------------------------------------*/
993 calculate_sizes (MonoMethodSignature
*sig
, size_data
*sz
,
994 gboolean string_ctor
)
996 guint i
, fr
, gr
, size
, nWords
;
997 int nParm
= sig
->hasthis
+ sig
->param_count
;
998 guint32 simpletype
, align
;
999 CallInfo
*cinfo
= g_malloc0 (sizeof (CallInfo
) + sizeof (ArgInfo
) * nParm
);
1003 cinfo
->struct_ret
= 0;
1005 sz
->stack_size
= S390_MINIMAL_STACK_SIZE
;
1007 sz
->local_size
= S390_MINIMAL_STACK_SIZE
;
1010 /*----------------------------------------------------------*/
1011 /* We determine the size of the return code/stack in case we*/
1012 /* need to reserve a register to be used to address a stack */
1013 /* area that the callee will use. */
1014 /*----------------------------------------------------------*/
1016 if (sig
->ret
->byref
|| string_ctor
) {
1019 simpletype
= sig
->ret
->type
;
1021 switch (simpletype
) {
1022 case MONO_TYPE_BOOLEAN
:
1027 case MONO_TYPE_CHAR
:
1032 case MONO_TYPE_CLASS
:
1033 case MONO_TYPE_OBJECT
:
1034 case MONO_TYPE_SZARRAY
:
1035 case MONO_TYPE_ARRAY
:
1037 case MONO_TYPE_STRING
:
1038 cinfo
->ret
.reg
= s390_r2
;
1043 cinfo
->ret
.reg
= s390_f0
;
1048 cinfo
->ret
.reg
= s390_r2
;
1051 case MONO_TYPE_VALUETYPE
:
1052 if (sig
->ret
->data
.klass
->enumtype
) {
1053 simpletype
= sig
->ret
->data
.klass
->enum_basetype
->type
;
1057 size
= mono_class_native_size (sig
->ret
->data
.klass
, &align
);
1059 size
= mono_class_value_size (sig
->ret
->data
.klass
, &align
);
1060 cinfo
->ret
.reg
= s390_r2
;
1061 cinfo
->struct_ret
= 1;
1062 cinfo
->ret
.size
= size
;
1063 cinfo
->ret
.vtsize
= size
;
1064 cinfo
->ret
.offset
= sz
->stack_size
;
1065 sz
->stack_size
+= S390_ALIGN(size
, align
);
1068 case MONO_TYPE_VOID
:
1071 g_error ("Can't handle as return value 0x%x", sig
->ret
->type
);
1076 add_general (&gr
, sz
, cinfo
->args
+nParm
, TRUE
);
1077 cinfo
->args
[nParm
].size
= sizeof(gpointer
);
1081 /*----------------------------------------------------------*/
1082 /* We determine the size of the parameter code and stack */
1083 /* requirements by checking the types and sizes of the */
1085 /*----------------------------------------------------------*/
1087 for (i
= 0; i
< sig
->param_count
; ++i
) {
1088 if (sig
->params
[i
]->byref
) {
1089 add_general (&gr
, sz
, cinfo
->args
+nParm
, TRUE
);
1090 cinfo
->args
[nParm
].size
= sizeof(gpointer
);
1094 simpletype
= sig
->params
[i
]->type
;
1096 switch (simpletype
) {
1097 case MONO_TYPE_BOOLEAN
:
1100 cinfo
->args
[nParm
].size
= sizeof(char);
1101 add_general (&gr
, sz
, cinfo
->args
+nParm
, TRUE
);
1106 case MONO_TYPE_CHAR
:
1107 cinfo
->args
[nParm
].size
= sizeof(short);
1108 add_general (&gr
, sz
, cinfo
->args
+nParm
, TRUE
);
1113 cinfo
->args
[nParm
].size
= sizeof(int);
1114 add_general (&gr
, sz
, cinfo
->args
+nParm
, TRUE
);
1120 case MONO_TYPE_CLASS
:
1121 case MONO_TYPE_OBJECT
:
1122 case MONO_TYPE_STRING
:
1123 case MONO_TYPE_SZARRAY
:
1124 case MONO_TYPE_ARRAY
:
1125 cinfo
->args
[nParm
].size
= sizeof(gpointer
);
1126 add_general (&gr
, sz
, cinfo
->args
+nParm
, TRUE
);
1129 case MONO_TYPE_VALUETYPE
:
1130 if (sig
->params
[i
]->data
.klass
->enumtype
) {
1131 simpletype
= sig
->params
[i
]->data
.klass
->enum_basetype
->type
;
1132 goto enum_calc_size
;
1135 size
= mono_class_native_size (sig
->params
[i
]->data
.klass
, &align
);
1137 size
= mono_class_value_size (sig
->params
[i
]->data
.klass
, &align
);
1138 nWords
= (size
+ sizeof(gpointer
) - 1) /
1141 cinfo
->args
[nParm
].vtsize
= 0;
1142 cinfo
->args
[nParm
].size
= 0;
1143 cinfo
->args
[nParm
].offparm
= sz
->local_size
;
1146 /*----------------------------------*/
1147 /* On S/390, structures of size 1, */
1148 /* 2, 4, and 8 bytes are passed in */
1149 /* (a) register(s). */
1150 /*----------------------------------*/
1155 add_general(&gr
, sz
, cinfo
->args
+nParm
, TRUE
);
1156 cinfo
->args
[nParm
].size
= sizeof(int);
1157 cinfo
->args
[nParm
].regtype
= RegTypeStructByVal
;
1161 add_general(&gr
, sz
, cinfo
->args
+nParm
, FALSE
);
1162 cinfo
->args
[nParm
].size
= sizeof(long long);
1163 cinfo
->args
[nParm
].regtype
= RegTypeStructByVal
;
1167 add_general(&gr
, sz
, cinfo
->args
+nParm
, TRUE
);
1168 cinfo
->args
[nParm
].size
= sizeof(int);
1169 cinfo
->args
[nParm
].regtype
= RegTypeStructByVal
;
1170 cinfo
->args
[nParm
].vtsize
= size
;
1171 sz
->code_size
+= 40;
1174 sz
->local_size
+= sizeof(long);
1178 cinfo
->args
[nParm
].size
= sizeof(long long);
1179 add_general (&gr
, sz
, cinfo
->args
+nParm
, FALSE
);
1183 cinfo
->args
[nParm
].size
= sizeof(float);
1184 if (fr
<= S390_LAST_FPARG_REG
) {
1185 cinfo
->args
[nParm
].regtype
= RegTypeFP
;
1186 cinfo
->args
[nParm
].reg
= fr
;
1191 cinfo
->args
[nParm
].offset
= sz
->stack_size
;
1192 cinfo
->args
[nParm
].reg
= STK_BASE
;
1193 cinfo
->args
[nParm
].regtype
= RegTypeBase
;
1195 sz
->stack_size
+= 4;
1200 cinfo
->args
[nParm
].size
= sizeof(double);
1201 if (fr
<= S390_LAST_FPARG_REG
) {
1202 cinfo
->args
[nParm
].regtype
= RegTypeFP
;
1203 cinfo
->args
[nParm
].reg
= fr
;
1207 sz
->stack_size
= S390_ALIGN(sz
->stack_size
,
1208 S390_STACK_ALIGNMENT
);
1209 cinfo
->args
[nParm
].offset
= sz
->stack_size
;
1210 cinfo
->args
[nParm
].reg
= STK_BASE
;
1211 cinfo
->args
[nParm
].regtype
= RegTypeBase
;
1213 sz
->stack_size
+= 8;
1218 g_error ("Can't trampoline 0x%x", sig
->params
[i
]->type
);
1223 /* align stack size */
1224 sz
->stack_size
= S390_ALIGN(sz
->stack_size
, S390_STACK_ALIGNMENT
);
1225 cinfo
->stack_usage
= sz
->stack_size
;
1229 /*========================= End of Function ========================*/
1231 /*------------------------------------------------------------------*/
1233 /* Name - mono_arch_allocate_vars */
1235 /* Function - Set var information according to the calling */
1236 /* convention for S/390. The local var stuff should */
1237 /* most likely be split in another method. */
1239 /* Parameter - @m - Compile unit. */
1241 /*------------------------------------------------------------------*/
1244 mono_arch_allocate_vars (MonoCompile
*m
)
1246 MonoMethodSignature
*sig
;
1247 MonoMethodHeader
*header
;
1251 int iParm
, iVar
, offset
, size
, align
, curinst
;
1252 int frame_reg
= STK_BASE
;
1255 header
= ((MonoMethodNormal
*)m
->method
)->header
;
1258 * We use the frame register also for any method that has
1259 * filter clauses. This way, when the handlers are called,
1260 * the code will reference local variables using the frame reg instead of
1261 * the stack pointer: if we had to restore the stack pointer, we'd
1262 * corrupt the method frames that are already on the stack (since
1263 * filters get called before stack unwinding happens) when the filter
1264 * code would call any method.
1266 // if ((m->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses)
1267 if (m
->flags
& MONO_CFG_HAS_ALLOCA
)
1268 frame_reg
= s390_r11
;
1270 m
->frame_reg
= frame_reg
;
1272 if (frame_reg
!= STK_BASE
)
1273 m
->used_int_regs
|= 1 << frame_reg
;
1275 sig
= m
->method
->signature
;
1277 cinfo
= calculate_sizes (sig
, &sz
, sig
->pinvoke
);
1279 if (cinfo
->struct_ret
) {
1280 m
->ret
->opcode
= OP_REGVAR
;
1281 m
->ret
->inst_c0
= s390_r2
;
1283 /* FIXME: handle long and FP values */
1284 switch (sig
->ret
->type
) {
1285 case MONO_TYPE_VOID
:
1288 m
->ret
->opcode
= OP_REGVAR
;
1289 m
->ret
->dreg
= s390_r2
;
1294 /*--------------------------------------------------------------*/
1295 /* local vars are at a positive offset from the stack pointer */
1297 /* also note that if the function uses alloca, we use s390_r11 */
1298 /* to point at the local variables. */
1299 /* add parameter area size for called functions */
1300 /*--------------------------------------------------------------*/
1301 offset
= (m
->param_area
+ S390_MINIMAL_STACK_SIZE
);
1303 if (cinfo
->struct_ret
) {
1305 offset
= S390_ALIGN(offset
, sizeof(gpointer
));
1306 inst
->inst_offset
= offset
;
1307 inst
->opcode
= OP_REGOFFSET
;
1308 inst
->inst_basereg
= frame_reg
;
1309 offset
+= sizeof(gpointer
);
1313 inst
= m
->varinfo
[0];
1314 if (inst
->opcode
!= OP_REGVAR
) {
1315 inst
->opcode
= OP_REGOFFSET
;
1316 inst
->inst_basereg
= frame_reg
;
1317 offset
= S390_ALIGN(offset
, sizeof(gpointer
));
1318 inst
->inst_offset
= offset
;
1319 offset
+= sizeof (gpointer
);
1326 eArg
= sig
->param_count
+ sArg
;
1328 for (iParm
= sArg
; iParm
< eArg
; ++iParm
) {
1329 inst
= m
->varinfo
[curinst
];
1330 if (inst
->opcode
!= OP_REGVAR
) {
1331 if (cinfo
->args
[iParm
].regtype
== RegTypeStructByVal
) {
1332 if (cinfo
->args
[iParm
].vtsize
!= 0) {
1333 inst
->opcode
= OP_S390_LOADARG
;
1334 inst
->inst_basereg
= frame_reg
;
1335 size
= sizeof(long);
1336 offset
= S390_ALIGN(offset
, size
);
1337 inst
->inst_offset
= offset
;
1339 inst
->opcode
= OP_S390_ARGPTR
;
1340 inst
->inst_basereg
= frame_reg
;
1341 size
= cinfo
->args
[iParm
].size
;
1342 offset
= S390_ALIGN(offset
, size
);
1343 inst
->inst_offset
= offset
;
1346 if (cinfo
->args
[iParm
].reg
!= STK_BASE
) {
1347 inst
->opcode
= OP_REGOFFSET
;
1348 inst
->inst_basereg
= frame_reg
;
1349 size
= (cinfo
->args
[iParm
].size
< 8
1351 : sizeof(long long));
1352 offset
= S390_ALIGN(offset
, size
);
1353 inst
->inst_offset
= offset
;
1355 inst
->opcode
= OP_S390_STKARG
;
1356 inst
->inst_basereg
= frame_reg
;
1357 size
= (cinfo
->args
[iParm
].size
< 4
1358 ? 4 - cinfo
->args
[iParm
].size
1360 inst
->inst_offset
= cinfo
->args
[iParm
].offset
+
1362 // inst->unused = stackOffset;
1364 size
= sizeof(long);
1372 curinst
= m
->locals_start
;
1373 for (iVar
= curinst
; iVar
< m
->num_varinfo
; ++iVar
) {
1374 inst
= m
->varinfo
[iVar
];
1375 if (inst
->opcode
== OP_REGVAR
)
1378 /* inst->unused indicates native sized value types, this is used by the
1379 * pinvoke wrappers when they call functions returning structure */
1380 if (inst
->unused
&& MONO_TYPE_ISSTRUCT (inst
->inst_vtype
))
1381 size
= mono_class_native_size (inst
->inst_vtype
->data
.klass
, &align
);
1383 size
= mono_type_size (inst
->inst_vtype
, &align
);
1385 offset
= S390_ALIGN(offset
, align
);
1386 inst
->inst_offset
= offset
;
1387 inst
->opcode
= OP_REGOFFSET
;
1388 inst
->inst_basereg
= frame_reg
;
1390 //DEBUG (g_print("allocating local %d to %d\n", iVar, inst->inst_offset));
1393 // if (sig->hasthis)
1394 // curinst = sArg = 1;
1396 // curinst = sArg = 0;
1399 /*------------------------------------------------------*/
1400 /* Allow space for the trace method stack area if needed*/
1401 /*------------------------------------------------------*/
1402 if (mono_jit_trace_calls
!= NULL
&& mono_trace_eval (m
))
1403 offset
+= S390_TRACE_STACK_SIZE
;
1405 /*------------------------------------------------------*/
1406 /* Reserve space to save LMF and caller saved registers */
1407 /*------------------------------------------------------*/
1408 if (m
->method
->save_lmf
)
1409 offset
+= sizeof (MonoLMF
);
1411 /*------------------------------------------------------*/
1412 /* align the offset */
1413 /*------------------------------------------------------*/
1414 m
->stack_offset
= S390_ALIGN(offset
, S390_STACK_ALIGNMENT
);
1418 /*========================= End of Function ========================*/
1420 /*------------------------------------------------------------------*/
1422 /* Name - mono_arch_call_opcode */
1424 /* Function - Take the arguments and generate the arch-specific */
1425 /* instructions to properly call the function. This */
1426 /* includes pushing, moving argments to the correct */
1429 /* Note - FIXME: We need an alignment solution for */
1430 /* enter_method and mono_arch_call_opcode, currently */
1431 /* alignment in mono_arch_call_opcode is computed */
1432 /* without arch_get_argument_info. */
1434 /*------------------------------------------------------------------*/
1437 mono_arch_call_opcode (MonoCompile
*cfg
, MonoBasicBlock
* bb
, MonoCallInst
*call
, int is_virtual
) {
1439 MonoMethodSignature
*sig
;
1440 int i
, n
, lParamArea
;
1445 sig
= call
->signature
;
1446 n
= sig
->param_count
+ sig
->hasthis
;
1447 DEBUG (g_print ("Call requires: %d parameters\n",n
));
1449 cinfo
= calculate_sizes (sig
, &sz
, sig
->pinvoke
);
1450 if (cinfo
->struct_ret
)
1451 call
->used_iregs
|= 1 << cinfo
->struct_ret
;
1453 for (i
= 0; i
< n
; ++i
) {
1454 ainfo
= cinfo
->args
+ i
;
1455 DEBUG (g_print ("Parameter %d - Register: %d Type: %d\n",
1456 i
+1,ainfo
->reg
,ainfo
->regtype
));
1457 if (is_virtual
&& i
== 0) {
1458 /* the argument will be attached to the call instrucion */
1459 in
= call
->args
[i
];
1460 call
->used_iregs
|= 1 << ainfo
->reg
;
1462 MONO_INST_NEW (cfg
, arg
, OP_OUTARG
);
1463 in
= call
->args
[i
];
1464 arg
->cil_code
= in
->cil_code
;
1465 arg
->inst_left
= in
;
1466 arg
->type
= in
->type
;
1467 /* prepend, we'll need to reverse them later */
1468 arg
->next
= call
->out_args
;
1469 call
->out_args
= arg
;
1470 if (ainfo
->regtype
== RegTypeGeneral
) {
1471 arg
->unused
= ainfo
->reg
;
1472 call
->used_iregs
|= 1 << ainfo
->reg
;
1473 if (arg
->type
== STACK_I8
)
1474 call
->used_iregs
|= 1 << (ainfo
->reg
+ 1);
1475 } else if (ainfo
->regtype
== RegTypeStructByAddr
) {
1476 arg
->unused
= ainfo
->reg
;
1477 call
->used_iregs
|= 1 << ainfo
->reg
;
1478 } else if (ainfo
->regtype
== RegTypeStructByVal
) {
1479 if (ainfo
->reg
!= STK_BASE
) {
1480 switch (ainfo
->size
) {
1485 call
->used_iregs
|= 1 << ainfo
->reg
;
1488 call
->used_iregs
|= 1 << ainfo
->reg
;
1489 call
->used_iregs
|= 1 << (ainfo
->reg
+1);
1493 arg
->sreg1
= ainfo
->reg
;
1494 arg
->opcode
= OP_OUTARG_VT
;
1495 if (ainfo
->vtsize
!= 0)
1496 arg
->unused
= -ainfo
->vtsize
;
1498 arg
->unused
= ainfo
->size
;
1499 arg
->inst_imm
= ainfo
->offset
;
1500 arg
->sreg2
= ainfo
->offparm
;
1501 } else if (ainfo
->regtype
== RegTypeBase
) {
1502 arg
->opcode
= OP_OUTARG
;
1503 arg
->unused
= ainfo
->reg
| (ainfo
->size
<< 8);
1504 arg
->inst_imm
= ainfo
->offset
;
1505 } else if (ainfo
->regtype
== RegTypeFP
) {
1506 arg
->opcode
= OP_OUTARG_R8
;
1507 arg
->unused
= ainfo
->reg
;
1508 call
->used_fregs
|= 1 << ainfo
->reg
;
1509 if (ainfo
->size
== 4) {
1510 /* we reduce the precision */
1512 MONO_INST_NEW (cfg
, conv
, OP_FCONV_TO_R4
);
1513 conv
->inst_left
= arg
->inst_left
;
1514 arg
->inst_left
= conv
;
1517 g_assert_not_reached ();
1522 * Reverse the call->out_args list.
1525 MonoInst
*prev
= NULL
, *list
= call
->out_args
, *next
;
1532 call
->out_args
= prev
;
1534 call
->stack_usage
= cinfo
->stack_usage
;
1536 lParamArea
= cinfo
->stack_usage
- S390_MINIMAL_STACK_SIZE
;
1537 cfg
->param_area
= MAX (cfg
->param_area
, lParamArea
);
1538 cfg
->flags
|= MONO_CFG_HAS_CALLS
;
1539 /*----------------------------------------------------------*/
1540 /* should set more info in call, such as the stack space */
1541 /* used by the args that needs to be added back to esp */
1542 /*----------------------------------------------------------*/
1548 /*========================= End of Function ========================*/
1550 /*------------------------------------------------------------------*/
1552 /* Name - mono_arch_instrument_mem_needs */
1554 /* Function - Allow tracing to work with this interface (with */
1555 /* an optional argument). */
1557 /*------------------------------------------------------------------*/
1560 mono_arch_instrument_mem_needs (MonoMethod
*method
, int *stack
, int *code
)
1562 /* no stack room needed now (may be needed for FASTCALL-trace support) */
1564 /* split prolog-epilog requirements? */
1565 *code
= 50; /* max bytes needed: check this number */
1568 /*========================= End of Function ========================*/
1570 /*------------------------------------------------------------------*/
1572 /* Name - mono_arch_instrument_prolog */
1574 /* Function - Create an "instrumented" prolog. */
1576 /*------------------------------------------------------------------*/
1579 mono_arch_instrument_prolog (MonoCompile
*cfg
, void *func
, void *p
,
1580 gboolean enable_arguments
)
1586 parmOffset
= cfg
->stack_usage
- S390_TRACE_STACK_SIZE
;
1587 if (cfg
->method
->save_lmf
)
1588 parmOffset
-= sizeof(MonoLMF
);
1589 fpOffset
= parmOffset
+ (5*sizeof(gint32
));
1591 s390_stm (code
, s390_r2
, s390_r6
, STK_BASE
, parmOffset
);
1592 s390_std (code
, s390_f0
, 0, STK_BASE
, fpOffset
);
1593 s390_std (code
, s390_f1
, 0, STK_BASE
, fpOffset
+sizeof(gdouble
));
1594 s390_std (code
, s390_f2
, 0, STK_BASE
, fpOffset
+2*sizeof(gdouble
));
1595 s390_basr (code
, s390_r13
, 0);
1597 s390_word (code
, cfg
->method
);
1598 s390_word (code
, func
);
1599 s390_l (code
, s390_r2
, 0, s390_r13
, 4);
1600 s390_la (code
, s390_r3
, 0, STK_BASE
, parmOffset
);
1601 s390_lr (code
, s390_r4
, STK_BASE
);
1602 s390_ahi (code
, s390_r4
, cfg
->stack_usage
);
1603 s390_l (code
, s390_r1
, 0, s390_r13
, 8);
1604 s390_basr (code
, s390_r14
, s390_r1
);
1605 s390_ld (code
, s390_f2
, 0, STK_BASE
, fpOffset
+2*sizeof(gdouble
));
1606 s390_ld (code
, s390_f1
, 0, STK_BASE
, fpOffset
+sizeof(gdouble
));
1607 s390_ld (code
, s390_f0
, 0, STK_BASE
, fpOffset
);
1608 s390_lm (code
, s390_r2
, s390_r6
, STK_BASE
, parmOffset
);
1613 /*========================= End of Function ========================*/
1615 /*------------------------------------------------------------------*/
1617 /* Name - mono_arch_instrument_epilog */
1619 /* Function - Create an epilog that will handle the returned */
1620 /* values used in instrumentation. */
1622 /*------------------------------------------------------------------*/
1625 mono_arch_instrument_epilog (MonoCompile
*cfg
, void *func
, void *p
, gboolean enable_arguments
)
1628 int save_mode
= SAVE_NONE
,
1630 MonoMethod
*method
= cfg
->method
;
1631 int rtype
= method
->signature
->ret
->type
;
1633 saveOffset
= cfg
->stack_usage
- S390_TRACE_STACK_SIZE
;
1634 if (method
->save_lmf
)
1635 saveOffset
-= sizeof(MonoLMF
);
1639 case MONO_TYPE_VOID
:
1640 /* special case string .ctor icall */
1641 if (strcmp (".ctor", method
->name
) && method
->klass
== mono_defaults
.string_class
)
1642 save_mode
= SAVE_ONE
;
1644 save_mode
= SAVE_NONE
;
1648 save_mode
= SAVE_TWO
;
1652 save_mode
= SAVE_FP
;
1654 case MONO_TYPE_VALUETYPE
:
1655 if (method
->signature
->ret
->data
.klass
->enumtype
) {
1656 rtype
= method
->signature
->ret
->data
.klass
->enum_basetype
->type
;
1659 save_mode
= SAVE_STRUCT
;
1662 save_mode
= SAVE_ONE
;
1666 switch (save_mode
) {
1668 s390_stm (code
, s390_r2
, s390_r3
, cfg
->frame_reg
, saveOffset
);
1669 if (enable_arguments
) {
1670 s390_lr (code
, s390_r4
, s390_r3
);
1671 s390_lr (code
, s390_r3
, s390_r2
);
1675 s390_st (code
, s390_r2
, 0, cfg
->frame_reg
, saveOffset
);
1676 if (enable_arguments
) {
1677 s390_lr (code
, s390_r3
, s390_r2
);
1681 s390_std (code
, s390_f0
, 0, cfg
->frame_reg
, saveOffset
);
1682 if (enable_arguments
) {
1683 /* FIXME: what reg? */
1684 s390_ldr (code
, s390_f2
, s390_f0
);
1685 s390_lm (code
, s390_r3
, s390_r4
, cfg
->frame_reg
, saveOffset
);
1689 s390_st (code
, s390_r2
, 0, cfg
->frame_reg
, saveOffset
);
1690 if (enable_arguments
) {
1691 s390_l (code
, s390_r3
, 0, cfg
->frame_reg
,
1692 S390_MINIMAL_STACK_SIZE
+cfg
->param_area
);
1700 s390_basr (code
, s390_r13
, 0);
1702 s390_word (code
, cfg
->method
);
1703 s390_word (code
, func
);
1704 s390_l (code
, s390_r2
, 0, s390_r13
, 4);
1705 s390_l (code
, s390_r1
, 0, s390_r13
, 8);
1706 s390_basr (code
, s390_r14
, s390_r1
);
1708 switch (save_mode
) {
1710 s390_lm (code
, s390_r2
, s390_r3
, cfg
->frame_reg
, saveOffset
);
1713 s390_l (code
, s390_r2
, 0, cfg
->frame_reg
, saveOffset
);
1716 s390_ld (code
, s390_f0
, 0, cfg
->frame_reg
, saveOffset
);
1719 s390_l (code
, s390_r2
, 0, cfg
->frame_reg
, saveOffset
);
1729 /*========================= End of Function ========================*/
1731 /*------------------------------------------------------------------*/
1733 /* Name - peephole_pass */
1735 /* Function - Form a peephole pass at the code looking for */
1736 /* simple optimizations. */
1738 /*------------------------------------------------------------------*/
1741 peephole_pass (MonoCompile
*cfg
, MonoBasicBlock
*bb
)
1743 MonoInst
*ins
, *last_ins
= NULL
;
1748 switch (ins
->opcode
) {
1750 /* remove unnecessary multiplication with 1 */
1751 if (ins
->inst_imm
== 1) {
1752 if (ins
->dreg
!= ins
->sreg1
) {
1753 ins
->opcode
= OP_MOVE
;
1755 last_ins
->next
= ins
->next
;
1761 case OP_LOAD_MEMBASE
:
1762 case OP_LOADI4_MEMBASE
:
1764 * OP_STORE_MEMBASE_REG reg, offset(basereg)
1765 * OP_LOAD_MEMBASE offset(basereg), reg
1767 if (last_ins
&& (last_ins
->opcode
== OP_STOREI4_MEMBASE_REG
1768 || last_ins
->opcode
== OP_STORE_MEMBASE_REG
) &&
1769 ins
->inst_basereg
== last_ins
->inst_destbasereg
&&
1770 ins
->inst_offset
== last_ins
->inst_offset
) {
1771 if (ins
->dreg
== last_ins
->sreg1
) {
1772 last_ins
->next
= ins
->next
;
1776 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1777 ins
->opcode
= OP_MOVE
;
1778 ins
->sreg1
= last_ins
->sreg1
;
1782 * Note: reg1 must be different from the basereg in the second load
1783 * OP_LOAD_MEMBASE offset(basereg), reg1
1784 * OP_LOAD_MEMBASE offset(basereg), reg2
1786 * OP_LOAD_MEMBASE offset(basereg), reg1
1787 * OP_MOVE reg1, reg2
1789 } if (last_ins
&& (last_ins
->opcode
== OP_LOADI4_MEMBASE
1790 || last_ins
->opcode
== OP_LOAD_MEMBASE
) &&
1791 ins
->inst_basereg
!= last_ins
->dreg
&&
1792 ins
->inst_basereg
== last_ins
->inst_basereg
&&
1793 ins
->inst_offset
== last_ins
->inst_offset
) {
1795 if (ins
->dreg
== last_ins
->dreg
) {
1796 last_ins
->next
= ins
->next
;
1800 ins
->opcode
= OP_MOVE
;
1801 ins
->sreg1
= last_ins
->dreg
;
1804 //g_assert_not_reached ();
1808 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1809 * OP_LOAD_MEMBASE offset(basereg), reg
1811 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1812 * OP_ICONST reg, imm
1814 } else if (last_ins
&& (last_ins
->opcode
== OP_STOREI4_MEMBASE_IMM
1815 || last_ins
->opcode
== OP_STORE_MEMBASE_IMM
) &&
1816 ins
->inst_basereg
== last_ins
->inst_destbasereg
&&
1817 ins
->inst_offset
== last_ins
->inst_offset
) {
1818 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1819 ins
->opcode
= OP_ICONST
;
1820 ins
->inst_c0
= last_ins
->inst_imm
;
1821 g_assert_not_reached (); // check this rule
1825 case OP_LOADU1_MEMBASE
:
1826 case OP_LOADI1_MEMBASE
:
1827 if (last_ins
&& (last_ins
->opcode
== OP_STOREI1_MEMBASE_REG
) &&
1828 ins
->inst_basereg
== last_ins
->inst_destbasereg
&&
1829 ins
->inst_offset
== last_ins
->inst_offset
) {
1830 if (ins
->dreg
== last_ins
->sreg1
) {
1831 last_ins
->next
= ins
->next
;
1835 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1836 ins
->opcode
= OP_MOVE
;
1837 ins
->sreg1
= last_ins
->sreg1
;
1841 case OP_LOADU2_MEMBASE
:
1842 case OP_LOADI2_MEMBASE
:
1843 if (last_ins
&& (last_ins
->opcode
== OP_STOREI2_MEMBASE_REG
) &&
1844 ins
->inst_basereg
== last_ins
->inst_destbasereg
&&
1845 ins
->inst_offset
== last_ins
->inst_offset
) {
1846 if (ins
->dreg
== last_ins
->sreg1
) {
1847 last_ins
->next
= ins
->next
;
1851 ins
->opcode
= OP_MOVE
;
1852 ins
->sreg1
= last_ins
->sreg1
;
1862 if (ins
->dreg
== ins
->sreg1
) {
1864 last_ins
->next
= ins
->next
;
1869 * OP_MOVE sreg, dreg
1870 * OP_MOVE dreg, sreg
1872 if (last_ins
&& last_ins
->opcode
== OP_MOVE
&&
1873 ins
->sreg1
== last_ins
->dreg
&&
1874 ins
->dreg
== last_ins
->sreg1
) {
1875 last_ins
->next
= ins
->next
;
1884 bb
->last_ins
= last_ins
;
1887 /*========================= End of Function ========================*/
1889 /*------------------------------------------------------------------*/
1891 /* Name - mono_spillvar_offset */
1893 /* Function - Returns the offset used by spillvar. It allocates */
1894 /* a new spill variable if necessary. */
1896 /*------------------------------------------------------------------*/
1899 mono_spillvar_offset (MonoCompile
*cfg
, int spillvar
)
1901 MonoSpillInfo
**si
, *info
;
1904 si
= &cfg
->spill_info
;
1906 while (i
<= spillvar
) {
1909 *si
= info
= mono_mempool_alloc (cfg
->mempool
, sizeof (MonoSpillInfo
));
1911 info
->offset
= cfg
->stack_offset
;
1912 cfg
->stack_offset
+= sizeof (gpointer
);
1916 return (*si
)->offset
;
1922 g_assert_not_reached ();
1926 /*========================= End of Function ========================*/
1928 /*------------------------------------------------------------------*/
1930 /* Name - mono_spillvar_offset_float */
1934 /*------------------------------------------------------------------*/
1937 mono_spillvar_offset_float (MonoCompile
*cfg
, int spillvar
)
1939 MonoSpillInfo
**si
, *info
;
1942 si
= &cfg
->spill_info_float
;
1944 while (i
<= spillvar
) {
1947 *si
= info
= mono_mempool_alloc (cfg
->mempool
, sizeof (MonoSpillInfo
));
1949 cfg
->stack_offset
= S390_ALIGN(cfg
->stack_offset
, S390_STACK_ALIGNMENT
);
1950 info
->offset
= cfg
->stack_offset
;
1951 cfg
->stack_offset
+= sizeof (double);
1955 return (*si
)->offset
;
1961 g_assert_not_reached ();
1965 /*========================= End of Function ========================*/
1967 /*------------------------------------------------------------------*/
1969 /* Name - print_ins */
1971 /* Function - Decode and print the instruction for tracing. */
1973 /*------------------------------------------------------------------*/
1976 print_ins (int i
, MonoInst
*ins
)
1978 const char *spec
= ins_spec
[ins
->opcode
];
1979 g_print ("\t%-2d %s", i
, mono_inst_name (ins
->opcode
));
1980 if (spec
[MONO_INST_DEST
]) {
1981 if (ins
->dreg
>= MONO_MAX_IREGS
)
1982 g_print (" R%d <-", ins
->dreg
);
1984 g_print (" %s <-", mono_arch_regname (ins
->dreg
));
1986 if (spec
[MONO_INST_SRC1
]) {
1987 if (ins
->sreg1
>= MONO_MAX_IREGS
)
1988 g_print (" R%d", ins
->sreg1
);
1990 g_print (" %s", mono_arch_regname (ins
->sreg1
));
1992 if (spec
[MONO_INST_SRC2
]) {
1993 if (ins
->sreg2
>= MONO_MAX_IREGS
)
1994 g_print (" R%d", ins
->sreg2
);
1996 g_print (" %s", mono_arch_regname (ins
->sreg2
));
1998 if (spec
[MONO_INST_CLOB
])
1999 g_print (" clobbers: %c", spec
[MONO_INST_CLOB
]);
2003 /*========================= End of Function ========================*/
2005 /*------------------------------------------------------------------*/
2007 /* Name - print_regtrack. */
2011 /*------------------------------------------------------------------*/
2014 print_regtrack (RegTrack
*t
, int num
)
2020 for (i
= 0; i
< num
; ++i
) {
2023 if (i
>= MONO_MAX_IREGS
) {
2024 g_snprintf (buf
, sizeof(buf
), "R%d", i
);
2027 r
= mono_arch_regname (i
);
2028 g_print ("liveness: %s [%d - %d]\n", r
, t
[i
].born_in
, t
[i
].last_use
);
2032 /*========================= End of Function ========================*/
2034 /*------------------------------------------------------------------*/
2036 /* Name - inst_list_prepend */
2038 /* Function - Prepend an instruction to the list. */
2040 /*------------------------------------------------------------------*/
2042 static inline InstList
*
2043 inst_list_prepend (MonoMemPool
*pool
, InstList
*list
, MonoInst
*data
)
2045 InstList
*item
= mono_mempool_alloc (pool
, sizeof (InstList
));
2054 /*========================= End of Function ========================*/
2056 /*------------------------------------------------------------------*/
2058 /* Name - get_register_force_spilling */
2060 /* Function - Force the spilling of the variable in the */
2061 /* symbolic register 'reg'. */
2063 /*------------------------------------------------------------------*/
2066 get_register_force_spilling (MonoCompile
*cfg
, InstList
*item
, MonoInst
*ins
, int reg
)
2071 sel
= cfg
->rs
->iassign
[reg
];
2073 spill
= ++cfg
->spill_count
;
2074 cfg
->rs
->iassign
[i
] = -spill
- 1;
2075 mono_regstate_free_int (cfg
->rs
, sel
);
2076 /*----------------------------------------------------------*/
2077 /* we need to create a spill var and insert a load to sel */
2078 /* after the current instruction */
2079 /*----------------------------------------------------------*/
2080 MONO_INST_NEW (cfg
, load
, OP_LOAD_MEMBASE
);
2082 load
->inst_basereg
= cfg
->frame_reg
;
2083 load
->inst_offset
= mono_spillvar_offset (cfg
, spill
);
2085 while (ins
->next
!= item
->prev
->data
)
2088 load
->next
= ins
->next
;
2090 DEBUG (g_print ("SPILLED LOAD (%d at 0x%08x(%%sp)) R%d (freed %s)\n",
2091 spill
, load
->inst_offset
, i
, mono_arch_regname (sel
)));
2092 i
= mono_regstate_alloc_int (cfg
->rs
, 1 << sel
);
2093 g_assert (i
== sel
);
2098 /*========================= End of Function ========================*/
2100 /*------------------------------------------------------------------*/
2102 /* Name - get_register_spilling */
2106 /*------------------------------------------------------------------*/
2109 get_register_spilling (MonoCompile
*cfg
, InstList
*item
, MonoInst
*ins
, guint32 regmask
, int reg
)
2114 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
));
2115 /* exclude the registers in the current instruction */
2116 if (reg
!= ins
->sreg1
&&
2117 (reg_is_freeable (ins
->sreg1
) ||
2118 (ins
->sreg1
>= MONO_MAX_IREGS
&&
2119 cfg
->rs
->iassign
[ins
->sreg1
] >= 0))) {
2120 if (ins
->sreg1
>= MONO_MAX_IREGS
)
2121 regmask
&= ~ (1 << cfg
->rs
->iassign
[ins
->sreg1
]);
2123 regmask
&= ~ (1 << ins
->sreg1
);
2124 DEBUG (g_print ("excluding sreg1 %s\n", mono_arch_regname (ins
->sreg1
)));
2126 if (reg
!= ins
->sreg2
&&
2127 (reg_is_freeable (ins
->sreg2
) ||
2128 (ins
->sreg2
>= MONO_MAX_IREGS
&&
2129 cfg
->rs
->iassign
[ins
->sreg2
] >= 0))) {
2130 if (ins
->sreg2
>= MONO_MAX_IREGS
)
2131 regmask
&= ~ (1 << cfg
->rs
->iassign
[ins
->sreg2
]);
2133 regmask
&= ~ (1 << ins
->sreg2
);
2134 DEBUG (g_print ("excluding sreg2 %s %d\n", mono_arch_regname (ins
->sreg2
), ins
->sreg2
));
2136 if (reg
!= ins
->dreg
&& reg_is_freeable (ins
->dreg
)) {
2137 regmask
&= ~ (1 << ins
->dreg
);
2138 DEBUG (g_print ("excluding dreg %s\n", mono_arch_regname (ins
->dreg
)));
2141 DEBUG (g_print ("available regmask: 0x%08x\n", regmask
));
2142 g_assert (regmask
); /* need at least a register we can free */
2144 /* we should track prev_use and spill the register that's farther */
2145 for (i
= 0; i
< MONO_MAX_IREGS
; ++i
) {
2146 if (regmask
& (1 << i
)) {
2148 DEBUG (g_print ("selected register %s has assignment %d\n", mono_arch_regname (sel
), cfg
->rs
->iassign
[sel
]));
2152 i
= cfg
->rs
->isymbolic
[sel
];
2153 spill
= ++cfg
->spill_count
;
2154 cfg
->rs
->iassign
[i
] = -spill
- 1;
2155 mono_regstate_free_int (cfg
->rs
, sel
);
2156 /* we need to create a spill var and insert a load to sel after the current instruction */
2157 MONO_INST_NEW (cfg
, load
, OP_LOAD_MEMBASE
);
2159 load
->inst_basereg
= cfg
->frame_reg
;
2160 load
->inst_offset
= mono_spillvar_offset (cfg
, spill
);
2162 while (ins
->next
!= item
->prev
->data
)
2165 load
->next
= ins
->next
;
2167 DEBUG (g_print ("SPILLED LOAD (%d at 0x%08x(%%sp)) R%d (freed %s)\n", spill
, load
->inst_offset
, i
, mono_arch_regname (sel
)));
2168 i
= mono_regstate_alloc_int (cfg
->rs
, 1 << sel
);
2169 g_assert (i
== sel
);
2174 /*========================= End of Function ========================*/
2176 /*------------------------------------------------------------------*/
2178 /* Name - get_float_register_spilling */
2182 /*------------------------------------------------------------------*/
2185 get_float_register_spilling (MonoCompile
*cfg
, InstList
*item
, MonoInst
*ins
, guint32 regmask
, int reg
)
2190 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
));
2191 /* exclude the registers in the current instruction */
2192 if (reg
!= ins
->sreg1
&&
2193 (freg_is_freeable (ins
->sreg1
) ||
2194 (ins
->sreg1
>= MONO_MAX_FREGS
&&
2195 cfg
->rs
->fassign
[ins
->sreg1
] >= 0))) {
2196 if (ins
->sreg1
>= MONO_MAX_FREGS
)
2197 regmask
&= ~ (1 << cfg
->rs
->fassign
[ins
->sreg1
]);
2199 regmask
&= ~ (1 << ins
->sreg1
);
2200 DEBUG (g_print ("excluding sreg1 %s\n", mono_arch_regname (ins
->sreg1
)));
2202 if (reg
!= ins
->sreg2
&&
2203 (freg_is_freeable (ins
->sreg2
) ||
2204 (ins
->sreg2
>= MONO_MAX_FREGS
&&
2205 cfg
->rs
->fassign
[ins
->sreg2
] >= 0))) {
2206 if (ins
->sreg2
>= MONO_MAX_FREGS
)
2207 regmask
&= ~ (1 << cfg
->rs
->fassign
[ins
->sreg2
]);
2209 regmask
&= ~ (1 << ins
->sreg2
);
2210 DEBUG (g_print ("excluding sreg2 %s %d\n", mono_arch_regname (ins
->sreg2
), ins
->sreg2
));
2212 if (reg
!= ins
->dreg
&& freg_is_freeable (ins
->dreg
)) {
2213 regmask
&= ~ (1 << ins
->dreg
);
2214 DEBUG (g_print ("excluding dreg %s\n", mono_arch_regname (ins
->dreg
)));
2217 DEBUG (g_print ("available regmask: 0x%08x\n", regmask
));
2218 g_assert (regmask
); /* need at least a register we can free */
2220 /* we should track prev_use and spill the register that's farther */
2221 for (i
= 0; i
< MONO_MAX_FREGS
; ++i
) {
2222 if (regmask
& (1 << i
)) {
2224 DEBUG (g_print ("selected register %s has assignment %d\n",
2225 mono_arch_regname (sel
), cfg
->rs
->fassign
[sel
]));
2229 i
= cfg
->rs
->fsymbolic
[sel
];
2230 spill
= ++cfg
->spill_count
;
2231 cfg
->rs
->fassign
[i
] = -spill
- 1;
2232 mono_regstate_free_float(cfg
->rs
, sel
);
2233 /* we need to create a spill var and insert a load to sel after the current instruction */
2234 MONO_INST_NEW (cfg
, load
, OP_LOADR8_MEMBASE
);
2236 load
->inst_basereg
= cfg
->frame_reg
;
2237 load
->inst_offset
= mono_spillvar_offset_float (cfg
, spill
);
2239 while (ins
->next
!= item
->prev
->data
)
2242 load
->next
= ins
->next
;
2244 DEBUG (g_print ("SPILLED LOAD (%d at 0x%08x(%%sp)) R%d (freed %s)\n", spill
, load
->inst_offset
, i
, mono_arch_regname (sel
)));
2245 i
= mono_regstate_alloc_float (cfg
->rs
, 1 << sel
);
2246 g_assert (i
== sel
);
2251 /*========================= End of Function ========================*/
2253 /*------------------------------------------------------------------*/
2255 /* Name - create_copy_ins */
2257 /* Function - Create an instruction to copy from reg to reg. */
2259 /*------------------------------------------------------------------*/
2262 create_copy_ins (MonoCompile
*cfg
, int dest
, int src
, MonoInst
*ins
)
2265 MONO_INST_NEW (cfg
, copy
, OP_MOVE
);
2269 copy
->next
= ins
->next
;
2272 DEBUG (g_print ("\tforced copy from %s to %s\n",
2273 mono_arch_regname (src
), mono_arch_regname (dest
)));
2277 /*========================= End of Function ========================*/
2279 /*------------------------------------------------------------------*/
2281 /* Name - create_copy_ins_float */
2283 /* Function - Create an instruction to copy from float reg to */
2286 /*------------------------------------------------------------------*/
2289 create_copy_ins_float (MonoCompile
*cfg
, int dest
, int src
, MonoInst
*ins
)
2292 MONO_INST_NEW (cfg
, copy
, OP_FMOVE
);
2296 copy
->next
= ins
->next
;
2299 DEBUG (g_print ("\tforced copy from %s to %s\n",
2300 mono_arch_regname (src
), mono_arch_regname (dest
)));
2304 /*========================= End of Function ========================*/
2306 /*------------------------------------------------------------------*/
2308 /* Name - create_spilled_store */
2310 /* Function - Spill register to storage. */
2312 /*------------------------------------------------------------------*/
2315 create_spilled_store (MonoCompile
*cfg
, int spill
, int reg
, int prev_reg
, MonoInst
*ins
)
2318 MONO_INST_NEW (cfg
, store
, OP_STORE_MEMBASE_REG
);
2320 store
->inst_destbasereg
= cfg
->frame_reg
;
2321 store
->inst_offset
= mono_spillvar_offset (cfg
, spill
);
2323 store
->next
= ins
->next
;
2326 DEBUG (g_print ("SPILLED STORE (%d at 0x%08x(%%sp)) R%d (from %s)\n",
2327 spill
, store
->inst_offset
, prev_reg
, mono_arch_regname (reg
)));
2331 /*========================= End of Function ========================*/
2333 /*------------------------------------------------------------------*/
2335 /* Name - create_spilled_store_float */
2337 /* Function - Spill floating point register to storage. */
2339 /*------------------------------------------------------------------*/
2342 create_spilled_store_float (MonoCompile
*cfg
, int spill
, int reg
, int prev_reg
, MonoInst
*ins
)
2345 MONO_INST_NEW (cfg
, store
, OP_STORER8_MEMBASE_REG
);
2347 store
->inst_destbasereg
= cfg
->frame_reg
;
2348 store
->inst_offset
= mono_spillvar_offset_float (cfg
, spill
);
2350 store
->next
= ins
->next
;
2353 DEBUG (g_print ("SPILLED STORE (%d at 0x%08x(%%sp)) R%d (from %s)\n",
2354 spill
, store
->inst_offset
, prev_reg
, mono_arch_regname (reg
)));
2358 /*========================= End of Function ========================*/
2360 /*------------------------------------------------------------------*/
2362 /* Name - insert_before_ins */
2364 /* Function - Insert an instruction before another. */
2366 /*------------------------------------------------------------------*/
2369 insert_before_ins (MonoInst
*ins
, InstList
*item
, MonoInst
* to_insert
)
2372 g_assert (item
->next
);
2373 prev
= item
->next
->data
;
2375 while (prev
->next
!= ins
)
2377 to_insert
->next
= ins
;
2378 prev
->next
= to_insert
;
2380 * needed otherwise in the next instruction we can add an ins to the
2381 * end and that would get past this instruction.
2383 item
->data
= to_insert
;
2386 /*========================= End of Function ========================*/
2388 /*------------------------------------------------------------------*/
2390 /* Name - alloc_int_reg */
2392 /* Function - Allocate a general register. */
2394 /*------------------------------------------------------------------*/
2397 alloc_int_reg (MonoCompile
*cfg
, InstList
*curinst
, MonoInst
*ins
, int sym_reg
, guint32 allow_mask
)
2399 int val
= cfg
->rs
->iassign
[sym_reg
];
2400 DEBUG (g_print ("Allocating a general register for %d (%d) with mask %08x\n",val
,sym_reg
,allow_mask
));
2404 /* the register gets spilled after this inst */
2407 val
= mono_regstate_alloc_int (cfg
->rs
, allow_mask
);
2409 val
= get_register_spilling (cfg
, curinst
, ins
, allow_mask
, sym_reg
);
2410 cfg
->rs
->iassign
[sym_reg
] = val
;
2411 /* add option to store before the instruction for src registers */
2413 create_spilled_store (cfg
, spill
, val
, sym_reg
, ins
);
2415 DEBUG (g_print ("Allocated %d for %d\n",val
,sym_reg
));
2416 cfg
->rs
->isymbolic
[val
] = sym_reg
;
2420 /*========================= End of Function ========================*/
2422 /*------------------------------------------------------------------*/
2424 /* Name - mono_arch_local_regalloc. */
2426 /* Function - We first scan the list of instructions and we */
2427 /* save the liveness information of each register */
2428 /* (when the register is first used, when its value */
2429 /* is set etc.). We also reverse the list of instr- */
2430 /* uctions (in the InstList list) because assigning */
2431 /* registers backwards allows for more tricks to be */
2434 /*------------------------------------------------------------------*/
2437 mono_arch_local_regalloc (MonoCompile
*cfg
, MonoBasicBlock
*bb
)
2440 MonoRegState
*rs
= cfg
->rs
;
2442 RegTrack
*reginfo
, *reginfof
;
2443 RegTrack
*reginfo1
, *reginfo2
, *reginfod
;
2444 InstList
*tmp
, *reversed
= NULL
;
2446 guint32 src1_mask
, src2_mask
, dest_mask
;
2447 guint32 cur_iregs
, cur_fregs
;
2451 rs
->next_vireg
= bb
->max_ireg
;
2452 rs
->next_vfreg
= bb
->max_freg
;
2453 mono_regstate_assign (rs
);
2454 reginfo
= mono_mempool_alloc0 (cfg
->mempool
, sizeof (RegTrack
) * rs
->next_vireg
);
2455 reginfof
= mono_mempool_alloc0 (cfg
->mempool
, sizeof (RegTrack
) * rs
->next_vfreg
);
2456 rs
->ifree_mask
= S390_CALLER_REGS
;
2457 rs
->ffree_mask
= S390_CALLER_FREGS
;
2461 DEBUG (g_print ("LOCAL regalloc: basic block: %d\n", bb
->block_num
));
2462 /* forward pass on the instructions to collect register liveness info */
2464 spec
= ins_spec
[ins
->opcode
];
2465 DEBUG (print_ins (i
, ins
));
2466 if (spec
[MONO_INST_CLOB
] == 'c') {
2467 MonoCallInst
* call
= (MonoCallInst
*)ins
;
2470 if (spec
[MONO_INST_SRC1
]) {
2471 if (spec
[MONO_INST_SRC1
] == 'f')
2472 reginfo1
= reginfof
;
2475 reginfo1
[ins
->sreg1
].prev_use
= reginfo1
[ins
->sreg1
].last_use
;
2476 reginfo1
[ins
->sreg1
].last_use
= i
;
2480 if (spec
[MONO_INST_SRC2
]) {
2481 if (spec
[MONO_INST_SRC2
] == 'f')
2482 reginfo2
= reginfof
;
2485 reginfo2
[ins
->sreg2
].prev_use
= reginfo2
[ins
->sreg2
].last_use
;
2486 reginfo2
[ins
->sreg2
].last_use
= i
;
2490 if (spec
[MONO_INST_DEST
]) {
2491 if (spec
[MONO_INST_DEST
] == 'f')
2492 reginfod
= reginfof
;
2495 if (spec
[MONO_INST_DEST
] != 'b') /* it's not just a base register */
2496 reginfod
[ins
->dreg
].killed_in
= i
;
2497 reginfod
[ins
->dreg
].prev_use
= reginfod
[ins
->dreg
].last_use
;
2498 reginfod
[ins
->dreg
].last_use
= i
;
2499 if (reginfod
[ins
->dreg
].born_in
== 0 || reginfod
[ins
->dreg
].born_in
> i
)
2500 reginfod
[ins
->dreg
].born_in
= i
;
2501 if (spec
[MONO_INST_DEST
] == 'l') {
2502 /* result in eax:edx, the virtual register is allocated sequentially */
2503 reginfod
[ins
->dreg
+ 1].prev_use
= reginfod
[ins
->dreg
+ 1].last_use
;
2504 reginfod
[ins
->dreg
+ 1].last_use
= i
;
2505 if (reginfod
[ins
->dreg
+ 1].born_in
== 0 || reginfod
[ins
->dreg
+ 1].born_in
> i
)
2506 reginfod
[ins
->dreg
+ 1].born_in
= i
;
2511 reversed
= inst_list_prepend (cfg
->mempool
, reversed
, ins
);
2516 cur_iregs
= S390_CALLER_REGS
;
2517 cur_fregs
= S390_CALLER_FREGS
;
2519 DEBUG (print_regtrack (reginfo
, rs
->next_vireg
));
2520 DEBUG (print_regtrack (reginfof
, rs
->next_vfreg
));
2523 int prev_dreg
, prev_sreg1
, prev_sreg2
;
2526 spec
= ins_spec
[ins
->opcode
];
2527 DEBUG (g_print ("processing:"));
2528 DEBUG (print_ins (i
, ins
));
2529 /* make the register available for allocation: FIXME add fp reg */
2530 if (ins
->opcode
== OP_SETREG
|| ins
->opcode
== OP_SETREGIMM
) {
2531 cur_iregs
|= 1 << ins
->dreg
;
2532 DEBUG (g_print ("adding %d to cur_iregs\n", ins
->dreg
));
2533 } else if (ins
->opcode
== OP_SETFREG
) {
2534 cur_fregs
|= 1 << ins
->dreg
;
2535 DEBUG (g_print ("adding %d to cur_fregs\n", ins
->dreg
));
2536 } else if (spec
[MONO_INST_CLOB
] == 'c') {
2537 MonoCallInst
*cinst
= (MonoCallInst
*)ins
;
2538 DEBUG (g_print ("excluding regs 0x%x from cur_iregs (0x%x)\n",
2539 cinst
->used_iregs
, cur_iregs
));
2540 DEBUG (g_print ("excluding fpregs 0x%x from cur_fregs (0x%x)\n",
2541 cinst
->used_fregs
, cur_fregs
));
2542 cur_iregs
&= ~cinst
->used_iregs
;
2543 cur_fregs
&= ~cinst
->used_fregs
;
2544 DEBUG (g_print ("available cur_iregs: 0x%x\n", cur_iregs
));
2545 DEBUG (g_print ("available cur_fregs: 0x%x\n", cur_fregs
));
2546 /*------------------------------------------------------------*/
2547 /* registers used by the calling convention are excluded from */
2548 /* allocation: they will be selectively enabled when they are */
2549 /* assigned by the special SETREG opcodes. */
2550 /*------------------------------------------------------------*/
2552 dest_mask
= src1_mask
= src2_mask
= cur_iregs
;
2553 /*------------------------------------------------------*/
2554 /* update for use with FP regs... */
2555 /*------------------------------------------------------*/
2556 if (spec
[MONO_INST_DEST
] == 'f') {
2557 dest_mask
= cur_fregs
;
2558 if (ins
->dreg
>= MONO_MAX_FREGS
) {
2559 val
= rs
->fassign
[ins
->dreg
];
2560 prev_dreg
= ins
->dreg
;
2564 /* the register gets spilled after this inst */
2567 val
= mono_regstate_alloc_float (rs
, dest_mask
);
2569 val
= get_float_register_spilling (cfg
, tmp
, ins
, dest_mask
, ins
->dreg
);
2570 rs
->fassign
[ins
->dreg
] = val
;
2572 create_spilled_store_float (cfg
, spill
, val
, prev_dreg
, ins
);
2574 DEBUG (g_print ("\tassigned dreg %s to dest R%d\n",
2575 mono_arch_regname (val
), ins
->dreg
));
2576 rs
->fsymbolic
[val
] = prev_dreg
;
2578 if (spec
[MONO_INST_CLOB
] == 'c' && ins
->dreg
!= s390_f0
) {
2579 /* this instruction only outputs to s390_f0, need to copy */
2580 create_copy_ins_float (cfg
, ins
->dreg
, s390_f0
, ins
);
2585 if (freg_is_freeable (ins
->dreg
) && prev_dreg
>= 0 && (reginfof
[prev_dreg
].born_in
>= i
|| !(cur_fregs
& (1 << ins
->dreg
)))) {
2586 DEBUG (g_print ("\tfreeable %s (R%d) (born in %d)\n", mono_arch_regname (ins
->dreg
), prev_dreg
, reginfo
[prev_dreg
].born_in
));
2587 mono_regstate_free_float (rs
, ins
->dreg
);
2589 } else if (ins
->dreg
>= MONO_MAX_IREGS
) {
2590 val
= rs
->iassign
[ins
->dreg
];
2591 prev_dreg
= ins
->dreg
;
2595 /* the register gets spilled after this inst */
2598 val
= mono_regstate_alloc_int (rs
, dest_mask
);
2600 val
= get_register_spilling (cfg
, tmp
, ins
, dest_mask
, ins
->dreg
);
2601 rs
->iassign
[ins
->dreg
] = val
;
2603 create_spilled_store (cfg
, spill
, val
, prev_dreg
, ins
);
2605 DEBUG (g_print ("\tassigned dreg %s to dest R%d (prev: R%d)\n",
2606 mono_arch_regname (val
), ins
->dreg
, prev_dreg
));
2607 rs
->isymbolic
[val
] = prev_dreg
;
2609 if (spec
[MONO_INST_DEST
] == 'l') {
2610 int hreg
= prev_dreg
+ 1;
2611 val
= rs
->iassign
[hreg
];
2615 /* the register gets spilled after this inst */
2618 val
= mono_regstate_alloc_int (rs
, dest_mask
);
2620 val
= get_register_spilling (cfg
, tmp
, ins
, dest_mask
, hreg
);
2621 rs
->iassign
[hreg
] = val
;
2623 create_spilled_store (cfg
, spill
, val
, hreg
, ins
);
2625 DEBUG (g_print ("\tassigned hreg %s to dest R%d\n", mono_arch_regname (val
), hreg
));
2626 rs
->isymbolic
[val
] = hreg
;
2627 /* FIXME:? ins->dreg = val; */
2628 if (ins
->dreg
== s390_r3
) {
2630 create_copy_ins (cfg
, val
, s390_r2
, ins
);
2631 } else if (ins
->dreg
== s390_r2
) {
2632 if (val
== s390_r3
) {
2634 create_copy_ins (cfg
, s390_r3
, s390_r0
, ins
);
2635 create_copy_ins (cfg
, s390_r2
, s390_r3
, ins
);
2636 create_copy_ins (cfg
, s390_r0
, s390_r2
, ins
);
2638 /* two forced copies */
2639 create_copy_ins (cfg
, ins
->dreg
, s390_r3
, ins
);
2640 create_copy_ins (cfg
, val
, s390_r2
, ins
);
2643 if (val
== s390_r2
) {
2644 create_copy_ins (cfg
, ins
->dreg
, s390_r2
, ins
);
2646 /* two forced copies */
2647 create_copy_ins (cfg
, val
, s390_r2
, ins
);
2648 create_copy_ins (cfg
, ins
->dreg
, s390_r3
, ins
);
2651 if (reg_is_freeable (val
) && hreg
>= 0 && (reginfo
[hreg
].born_in
>= i
&& !(cur_iregs
& (1 << val
)))) {
2652 DEBUG (g_print ("\tfreeable %s (R%d)\n", mono_arch_regname (val
), hreg
));
2653 mono_regstate_free_int (rs
, val
);
2655 } else if (spec
[MONO_INST_DEST
] == 'a' && ins
->dreg
!= s390_r2
&& spec
[MONO_INST_CLOB
] != 'd') {
2656 /* this instruction only outputs to s390_r2, need to copy */
2657 create_copy_ins (cfg
, ins
->dreg
, s390_r2
, ins
);
2662 if (spec
[MONO_INST_DEST
] == 'f' &&
2663 freg_is_freeable (ins
->dreg
) &&
2664 prev_dreg
>= 0 && (reginfof
[prev_dreg
].born_in
>= i
)) {
2665 DEBUG (g_print ("\tfreeable %s (R%d) (born in %d)\n", mono_arch_regname (ins
->dreg
), prev_dreg
, reginfo
[prev_dreg
].born_in
));
2666 mono_regstate_free_float (rs
, ins
->dreg
);
2667 } else if (spec
[MONO_INST_DEST
] != 'f' &&
2668 reg_is_freeable (ins
->dreg
) &&
2669 prev_dreg
>= 0 && (reginfo
[prev_dreg
].born_in
>= i
)) {
2670 DEBUG (g_print ("\tfreeable %s (R%d) (born in %d)\n", mono_arch_regname (ins
->dreg
), prev_dreg
, reginfo
[prev_dreg
].born_in
));
2671 mono_regstate_free_int (rs
, ins
->dreg
);
2673 if (spec
[MONO_INST_SRC1
] == 'f') {
2674 src1_mask
= cur_fregs
;
2675 if (ins
->sreg1
>= MONO_MAX_FREGS
) {
2676 val
= rs
->fassign
[ins
->sreg1
];
2677 prev_sreg1
= ins
->sreg1
;
2681 /* the register gets spilled after this inst */
2684 //g_assert (val == -1); /* source cannot be spilled */
2685 val
= mono_regstate_alloc_float (rs
, src1_mask
);
2687 val
= get_float_register_spilling (cfg
, tmp
, ins
, src1_mask
, ins
->sreg1
);
2688 rs
->fassign
[ins
->sreg1
] = val
;
2689 DEBUG (g_print ("\tassigned sreg1 %s to R%d\n", mono_arch_regname (val
), ins
->sreg1
));
2691 MonoInst
*store
= create_spilled_store_float (cfg
, spill
, val
, prev_sreg1
, NULL
);
2692 insert_before_ins (ins
, tmp
, store
);
2695 rs
->fsymbolic
[val
] = prev_sreg1
;
2700 } else if (ins
->sreg1
>= MONO_MAX_IREGS
) {
2701 val
= rs
->iassign
[ins
->sreg1
];
2702 prev_sreg1
= ins
->sreg1
;
2706 /* the register gets spilled after this inst */
2709 val
= mono_regstate_alloc_int (rs
, src1_mask
);
2711 val
= get_register_spilling (cfg
, tmp
, ins
,
2714 rs
->iassign
[ins
->sreg1
] = val
;
2715 DEBUG (g_print ("\tassigned sreg1 %s to R%d\n",
2716 mono_arch_regname (val
), ins
->sreg1
));
2719 store
= create_spilled_store (cfg
, spill
, val
,
2721 insert_before_ins (ins
, tmp
, store
);
2724 rs
->isymbolic
[val
] = prev_sreg1
;
2729 /*----------------------------------------------*/
2730 /* handle clobbering of sreg1 */
2731 /*----------------------------------------------*/
2732 if ((spec
[MONO_INST_CLOB
] == '1' ||
2733 spec
[MONO_INST_CLOB
] == 's') &&
2734 ins
->dreg
!= ins
->sreg1
) {
2736 copy
= create_copy_ins (cfg
, ins
->dreg
, ins
->sreg1
, NULL
);
2737 DEBUG (g_print ("\tneed to copy sreg1 %s to dreg %s\n",
2738 mono_arch_regname (ins
->sreg1
),
2739 mono_arch_regname (ins
->dreg
)));
2740 if (ins
->sreg2
== -1 || spec
[MONO_INST_CLOB
] == 's') {
2741 /* note: the copy is inserted before the current instruction! */
2742 insert_before_ins (ins
, tmp
, copy
);
2743 /* we set sreg1 to dest as well */
2744 prev_sreg1
= ins
->sreg1
= ins
->dreg
;
2746 /* inserted after the operation */
2747 copy
->next
= ins
->next
;
2752 if (spec
[MONO_INST_SRC2
] == 'f') {
2753 src2_mask
= cur_fregs
;
2754 if (ins
->sreg2
>= MONO_MAX_FREGS
) {
2755 val
= rs
->fassign
[ins
->sreg2
];
2756 prev_sreg2
= ins
->sreg2
;
2760 /* the register gets spilled after this inst */
2763 val
= mono_regstate_alloc_float (rs
, src2_mask
);
2765 val
= get_float_register_spilling (cfg
, tmp
, ins
, src2_mask
, ins
->sreg2
);
2766 rs
->fassign
[ins
->sreg2
] = val
;
2767 DEBUG (g_print ("\tassigned sreg2 %s to R%d\n", mono_arch_regname (val
), ins
->sreg2
));
2769 create_spilled_store_float (cfg
, spill
, val
, prev_sreg2
, ins
);
2771 rs
->fsymbolic
[val
] = prev_sreg2
;
2776 } else if (ins
->sreg2
>= MONO_MAX_IREGS
) {
2777 val
= rs
->iassign
[ins
->sreg2
];
2778 prev_sreg2
= ins
->sreg2
;
2782 /* the register gets spilled after this inst */
2785 val
= mono_regstate_alloc_int (rs
, src2_mask
);
2787 val
= get_register_spilling (cfg
, tmp
, ins
, src2_mask
, ins
->sreg2
);
2788 rs
->iassign
[ins
->sreg2
] = val
;
2789 DEBUG (g_print ("\tassigned sreg2 %s to R%d\n", mono_arch_regname (val
), ins
->sreg2
));
2791 create_spilled_store (cfg
, spill
, val
, prev_sreg2
, ins
);
2793 rs
->isymbolic
[val
] = prev_sreg2
;
2799 if (spec
[MONO_INST_CLOB
] == 'c') {
2801 guint32 clob_mask
= S390_CALLER_REGS
;
2802 for (j
= 0; j
< MONO_MAX_IREGS
; ++j
) {
2804 if ((clob_mask
& s
) && !(rs
->ifree_mask
& s
) && j
!= ins
->sreg1
) {
2805 //g_warning ("register %s busy at call site\n", mono_arch_regname (j));
2809 /*if (reg_is_freeable (ins->sreg1) && prev_sreg1 >= 0 && reginfo [prev_sreg1].born_in >= i) {
2810 DEBUG (g_print ("freeable %s\n", mono_arch_regname (ins->sreg1)));
2811 mono_regstate_free_int (rs, ins->sreg1);
2813 if (reg_is_freeable (ins->sreg2) && prev_sreg2 >= 0 && reginfo [prev_sreg2].born_in >= i) {
2814 DEBUG (g_print ("freeable %s\n", mono_arch_regname (ins->sreg2)));
2815 mono_regstate_free_int (rs, ins->sreg2);
2818 //DEBUG (print_ins (i, ins));
2823 /*========================= End of Function ========================*/
2825 /*------------------------------------------------------------------*/
2827 /* Name - emit_float_to_int */
2829 /* Function - Create instructions which will convert a floating */
2830 /* point value to integer. */
2832 /*------------------------------------------------------------------*/
2835 emit_float_to_int (MonoCompile
*cfg
, guchar
*code
, int dreg
, int sreg
, int size
, gboolean is_signed
)
2837 /* sreg is a float, dreg is an integer reg. */
2839 s390_cfdbr (code
, dreg
, 5, sreg
);
2841 s390_basr (code
, s390_r13
, 0);
2843 s390_double (code
, 0x41e0000000000000);
2844 s390_double (code
, 0x41f0000000000000);
2845 s390_ldr (code
, s390_f0
, sreg
);
2846 s390_cdb (code
, s390_f0
, 0, s390_r13
, 0);
2848 s390_sdb (code
, s390_f0
, 0, s390_r13
, 8);
2849 s390_cfdbr (code
, dreg
, 7, s390_f0
);
2851 s390_cfdbr (code
, dreg
, 5, sreg
);
2856 /*========================= End of Function ========================*/
2858 /*------------------------------------------------------------------*/
2860 /* Name - mono_emit_stack_alloc */
2864 /*------------------------------------------------------------------*/
2866 static unsigned char*
2867 mono_emit_stack_alloc (guchar
*code
, MonoInst
* tree
)
2872 /*========================= End of Function ========================*/
2874 /*------------------------------------------------------------------*/
2876 /* Name - mono_arch_output_basic_block */
2878 /* Function - Perform the "real" work of emitting instructions */
2879 /* that will do the work of in the basic block. */
2881 /*------------------------------------------------------------------*/
2884 mono_arch_output_basic_block (MonoCompile
*cfg
, MonoBasicBlock
*bb
)
2889 guint8
*code
= cfg
->native_code
+ cfg
->code_len
;
2890 MonoInst
*last_ins
= NULL
;
2891 guint last_offset
= 0;
2894 if (cfg
->opt
& MONO_OPT_PEEPHOLE
)
2895 peephole_pass (cfg
, bb
);
2897 /* we don't align basic blocks of loops on s390 */
2899 if (cfg
->verbose_level
> 2)
2900 g_print ("Basic block %d starting at offset 0x%x\n", bb
->block_num
, bb
->native_offset
);
2902 cpos
= bb
->max_offset
;
2904 if (cfg
->prof_options
& MONO_PROFILE_COVERAGE
) {
2905 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
2906 //g_assert (!mono_compile_aot);
2909 // cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
2910 /* this is not thread save, but good enough */
2911 /* fixme: howto handle overflows? */
2912 //x86_inc_mem (code, &cov->data [bb->dfn].count);
2917 offset
= code
- cfg
->native_code
;
2919 max_len
= ((guint8
*)ins_spec
[ins
->opcode
])[MONO_INST_LEN
];
2921 if (offset
> (cfg
->code_size
- max_len
- 16)) {
2922 cfg
->code_size
*= 2;
2923 cfg
->native_code
= g_realloc (cfg
->native_code
, cfg
->code_size
);
2924 code
= cfg
->native_code
+ offset
;
2927 switch (ins
->opcode
) {
2928 case OP_STOREI1_MEMBASE_IMM
:
2929 s390_lhi (code
, s390_r14
, ins
->inst_imm
);
2930 if (s390_is_uimm12(ins
->inst_offset
))
2931 s390_stc (code
, s390_r14
, 0, ins
->inst_destbasereg
, ins
->inst_offset
);
2933 s390_basr (code
, s390_r13
, 0);
2935 s390_word (code
, ins
->inst_offset
);
2936 s390_l (code
, s390_r13
, 0, s390_r13
, 4);
2937 s390_stc (code
, s390_r14
, s390_r13
, ins
->inst_destbasereg
, 0);
2940 case OP_STOREI2_MEMBASE_IMM
:
2941 s390_lhi (code
, s390_r14
, ins
->inst_imm
);
2942 if (s390_is_uimm12(ins
->inst_offset
)) {
2943 s390_sth (code
, s390_r14
, 0, ins
->inst_destbasereg
, ins
->inst_offset
);
2945 s390_basr (code
, s390_r14
, 0);
2947 s390_word (code
, ins
->inst_offset
);
2948 s390_l (code
, s390_r13
, 0, s390_r13
, 4);
2949 s390_sth (code
, s390_r14
, s390_r13
, ins
->inst_destbasereg
, 0);
2952 case OP_STORE_MEMBASE_IMM
:
2953 case OP_STOREI4_MEMBASE_IMM
:
2954 if (s390_is_imm16(ins
->inst_imm
)) {
2955 s390_lhi (code
, s390_r14
, ins
->inst_imm
);
2957 s390_basr (code
, s390_r13
, 0);
2959 s390_word (code
, ins
->inst_imm
);
2960 s390_l (code
, s390_r14
, 0, s390_r13
, 4);
2962 if (s390_is_uimm12(ins
->inst_offset
)) {
2963 s390_st (code
, s390_r14
, 0, ins
->inst_destbasereg
, ins
->inst_offset
);
2965 s390_basr (code
, s390_r13
, 0);
2967 s390_word (code
, ins
->inst_offset
);
2968 s390_l (code
, s390_r13
, 0, s390_r13
, 4);
2969 s390_st (code
, s390_r14
, s390_r13
, ins
->inst_destbasereg
, 0);
2972 case OP_STOREI1_MEMBASE_REG
:
2973 if (s390_is_uimm12(ins
->inst_offset
)) {
2974 s390_stc (code
, ins
->sreg1
, 0, ins
->inst_destbasereg
, ins
->inst_offset
);
2976 s390_basr (code
, s390_r13
, 0);
2978 s390_word (code
, ins
->inst_offset
);
2979 s390_l (code
, s390_r13
, 0, s390_r13
, 4);
2980 s390_stc (code
, ins
->sreg1
, s390_r13
, ins
->inst_destbasereg
, 0);
2983 case OP_STOREI2_MEMBASE_REG
:
2984 if (s390_is_uimm12(ins
->inst_offset
)) {
2985 s390_sth (code
, ins
->sreg1
, 0, ins
->inst_destbasereg
, ins
->inst_offset
);
2987 s390_basr (code
, s390_r13
, 0);
2989 s390_word (code
, ins
->inst_offset
);
2990 s390_l (code
, s390_r13
, 0, s390_r13
, 4);
2991 s390_sth (code
, ins
->sreg1
, s390_r13
, ins
->inst_destbasereg
, 0);
2994 case OP_STORE_MEMBASE_REG
:
2995 case OP_STOREI4_MEMBASE_REG
:
2996 if (s390_is_uimm12(ins
->inst_offset
)) {
2997 s390_st (code
, ins
->sreg1
, 0, ins
->inst_destbasereg
, ins
->inst_offset
);
2999 s390_basr (code
, s390_r13
, 0);
3001 s390_word (code
, ins
->inst_offset
);
3002 s390_l (code
, s390_r13
, 0, s390_r13
, 4);
3003 s390_st (code
, ins
->sreg1
, s390_r13
, ins
->inst_destbasereg
, 0);
3009 s390_basr (code
, s390_r13
, 0);
3011 s390_word (code
, ins
->inst_p0
);
3012 s390_l (code
, s390_r13
, 0, s390_r13
, 4);
3013 s390_l (code
, ins
->dreg
, 0, s390_r13
, 0);
3016 g_assert_not_reached ();
3018 case OP_LOAD_MEMBASE
:
3019 case OP_LOADI4_MEMBASE
:
3020 case OP_LOADU4_MEMBASE
:
3021 if (s390_is_uimm12(ins
->inst_offset
))
3022 s390_l (code
, ins
->dreg
, 0, ins
->inst_basereg
, ins
->inst_offset
);
3024 if (s390_is_imm16(ins
->inst_offset
)) {
3025 s390_lhi (code
, s390_r13
, ins
->inst_offset
);
3026 s390_l (code
, ins
->dreg
, s390_r13
, ins
->inst_basereg
, 0);
3028 s390_basr (code
, s390_r13
, 0);
3030 s390_word (code
, ins
->inst_offset
);
3031 s390_l (code
, s390_r13
, 0, s390_r13
, 4);
3032 s390_l (code
, ins
->dreg
, s390_r13
, ins
->inst_basereg
, 0);
3036 case OP_LOADU1_MEMBASE
:
3037 s390_lhi (code
, s390_r0
, 0);
3038 if (s390_is_uimm12(ins
->inst_offset
))
3039 s390_ic (code
, s390_r0
, 0, ins
->inst_basereg
, ins
->inst_offset
);
3041 s390_basr (code
, s390_r13
, 0);
3043 s390_word (code
, ins
->inst_offset
);
3044 s390_l (code
, s390_r13
, 0, s390_r13
, 4);
3045 s390_ic (code
, s390_r0
, s390_r13
, ins
->inst_basereg
, 0);
3047 s390_lr (code
, ins
->dreg
, s390_r0
);
3049 case OP_LOADI1_MEMBASE
:
3050 s390_lhi (code
, s390_r0
, 0);
3051 if (s390_is_uimm12(ins
->inst_offset
))
3052 s390_ic (code
, s390_r0
, 0, ins
->inst_basereg
, ins
->inst_offset
);
3054 s390_basr (code
, s390_r13
, 0);
3056 s390_word (code
, ins
->inst_offset
);
3057 s390_l (code
, s390_r13
, 0, s390_r13
, 4);
3058 s390_ic (code
, s390_r0
, s390_r13
, ins
->inst_basereg
, 0);
3060 s390_lhi (code
, s390_r13
, 0x80);
3061 s390_nr (code
, s390_r13
, s390_r0
);
3063 s390_lhi (code
, s390_r13
, 0xff00);
3064 s390_or (code
, s390_r0
, s390_r13
);
3065 s390_lr (code
, ins
->dreg
, s390_r0
);
3067 case OP_LOADU2_MEMBASE
:
3068 s390_lhi (code
, s390_r0
, 0);
3069 if (s390_is_uimm12(ins
->inst_offset
))
3070 s390_icm (code
, s390_r0
, 3, ins
->inst_basereg
, ins
->inst_offset
);
3072 s390_basr (code
, s390_r13
, 0);
3074 s390_word (code
, ins
->inst_offset
);
3075 s390_l (code
, s390_r13
, 0, s390_r13
, 4);
3076 s390_ar (code
, s390_r13
, ins
->inst_basereg
);
3077 s390_icm (code
, s390_r0
, 3, s390_r13
, 0);
3079 s390_lr (code
, ins
->dreg
, s390_r0
);
3081 case OP_LOADI2_MEMBASE
:
3082 s390_lhi (code
, s390_r0
, 0);
3083 if (s390_is_uimm12(ins
->inst_offset
))
3084 s390_lh (code
, s390_r0
, 0, ins
->inst_basereg
, ins
->inst_offset
);
3086 s390_basr (code
, s390_r13
, 0);
3088 s390_word (code
, ins
->inst_offset
);
3089 s390_l (code
, s390_r13
, 0, s390_r13
, 4);
3090 s390_lh (code
, s390_r0
, s390_r13
, ins
->inst_basereg
, 0);
3092 s390_lr (code
, ins
->dreg
, s390_r0
);
3095 s390_lhi (code
, s390_r0
, 0x80);
3096 if (ins
->dreg
!= ins
->sreg1
) {
3097 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3099 s390_nr (code
, s390_r0
, ins
->sreg1
);
3101 s390_lhi (code
, s390_r13
, -1);
3102 s390_sll (code
, s390_r13
, 0, 8);
3103 s390_or (code
, ins
->dreg
, s390_r13
);
3106 s390_lhi (code
, s390_r0
, 0x80);
3107 if (ins
->dreg
!= ins
->sreg1
) {
3108 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3110 s390_nr (code
, s390_r0
, ins
->sreg1
);
3112 s390_lhi (code
, s390_r13
, -1);
3113 s390_sll (code
, s390_r13
, 0, 16);
3114 s390_or (code
, ins
->dreg
, s390_r13
);
3117 s390_lhi (code
, s390_r0
, 0xff);
3118 if (ins
->dreg
!= ins
->sreg1
) {
3119 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3121 s390_nr (code
, ins
->dreg
, s390_r0
);
3124 s390_lhi (code
, s390_r0
, -1);
3125 s390_sll (code
, s390_r0
, 0, 16);
3126 s390_srl (code
, s390_r0
, 0, 16);
3127 if (ins
->dreg
!= ins
->sreg1
) {
3128 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3130 s390_nr (code
, ins
->dreg
, s390_r0
);
3134 ((ins
->next
->opcode
>= CEE_BNE_UN
) &&
3135 (ins
->next
->opcode
<= CEE_BLT_UN
)))
3136 s390_clr (code
, ins
->sreg1
, ins
->sreg2
);
3138 s390_cr (code
, ins
->sreg1
, ins
->sreg2
);
3140 case OP_COMPARE_IMM
:
3141 if (s390_is_imm16 (ins
->inst_imm
)) {
3142 s390_lhi (code
, s390_r0
, ins
->inst_imm
);
3144 ((ins
->next
->opcode
>= CEE_BNE_UN
) &&
3145 (ins
->next
->opcode
<= CEE_BLT_UN
)))
3146 s390_clr (code
, ins
->sreg1
, s390_r0
);
3148 s390_cr (code
, ins
->sreg1
, s390_r0
);
3151 s390_basr (code
, s390_r13
, 0);
3153 s390_word (code
, ins
->inst_imm
);
3155 ((ins
->next
->opcode
>= CEE_BNE_UN
) &&
3156 (ins
->next
->opcode
<= CEE_BLT_UN
)))
3157 s390_cl (code
, ins
->sreg1
, 0, s390_r13
, 4);
3159 s390_c (code
, ins
->sreg1
, 0, s390_r13
, 4);
3162 case OP_X86_TEST_NULL
:
3163 s390_ltr (code
, ins
->sreg1
, ins
->sreg1
);
3169 if (ins
->dreg
!= ins
->sreg1
) {
3170 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3172 s390_alr (code
, ins
->dreg
, ins
->sreg2
);
3175 if (ins
->dreg
!= ins
->sreg1
) {
3176 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3178 s390_ar (code
, ins
->dreg
, ins
->sreg2
);
3181 if (ins
->dreg
!= ins
->sreg1
) {
3182 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3184 s390_alcr (code
, ins
->dreg
, ins
->sreg2
);
3188 (ins
->next
->opcode
== OP_ADC_IMM
)) {
3189 s390_basr (code
, s390_r13
, 0);
3191 s390_word (code
, ins
->inst_imm
);
3192 if (ins
->dreg
!= ins
->sreg1
) {
3193 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3195 s390_al (code
, ins
->dreg
, 0, s390_r13
, 4);
3197 if (s390_is_imm16 (ins
->inst_imm
)) {
3198 if (ins
->dreg
!= ins
->sreg1
) {
3199 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3201 s390_ahi (code
, ins
->dreg
, ins
->inst_imm
);
3203 s390_basr (code
, s390_r13
, 0);
3205 s390_word (code
, ins
->inst_imm
);
3206 if (ins
->dreg
!= ins
->sreg1
) {
3207 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3209 s390_a (code
, ins
->dreg
, 0, s390_r13
, 4);
3214 if (s390_is_imm16 (ins
->inst_imm
)) {
3215 if (ins
->dreg
!= ins
->sreg1
) {
3216 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3218 s390_lhi (code
, s390_r0
, ins
->inst_imm
);
3219 s390_alcr (code
, ins
->dreg
, s390_r0
);
3221 s390_basr (code
, s390_r13
, 0);
3223 s390_word (code
, ins
->inst_imm
);
3224 s390_l (code
, s390_r13
, 0, s390_r13
, 4);
3225 s390_alcr (code
, ins
->dreg
, s390_r13
);
3229 if (ins
->dreg
!= ins
->sreg1
) {
3230 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3232 s390_sr (code
, ins
->dreg
, ins
->sreg2
);
3235 if (ins
->dreg
!= ins
->sreg1
) {
3236 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3238 s390_sr (code
, ins
->dreg
, ins
->sreg2
);
3241 if (ins
->dreg
!= ins
->sreg1
) {
3242 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3244 s390_slbr (code
, ins
->dreg
, ins
->sreg2
);
3247 if (s390_is_imm16 (-ins
->inst_imm
)) {
3248 if (ins
->dreg
!= ins
->sreg1
) {
3249 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3251 s390_ahi (code
, ins
->dreg
, -ins
->inst_imm
);
3253 s390_basr (code
, s390_r13
, 0);
3255 s390_word (code
, ins
->inst_imm
);
3256 if (ins
->dreg
!= ins
->sreg1
) {
3257 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3259 s390_s (code
, ins
->dreg
, 0, s390_r13
, 4);
3263 s390_basr (code
, s390_r13
, 0);
3265 s390_word (code
, ins
->inst_imm
);
3266 s390_sl (code
, ins
->dreg
, 0, s390_r13
, 4);
3269 if (ins
->sreg1
== ins
->dreg
) {
3270 s390_nr (code
, ins
->dreg
, ins
->sreg2
);
3273 if (ins
->sreg2
== ins
->dreg
) {
3274 s390_nr (code
, ins
->dreg
, ins
->sreg1
);
3277 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3278 s390_nr (code
, ins
->dreg
, ins
->sreg2
);
3283 if (s390_is_imm16 (ins
->inst_imm
)) {
3284 s390_lhi (code
, s390_r0
, ins
->inst_imm
);
3285 if (ins
->dreg
!= ins
->sreg1
) {
3286 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3288 s390_nr (code
, ins
->dreg
, s390_r0
);
3290 s390_basr (code
, s390_r13
, 0);
3292 s390_word (code
, ins
->inst_imm
);
3293 if (ins
->dreg
!= ins
->sreg1
) {
3294 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3296 s390_n (code
, ins
->dreg
, 0, s390_r13
, 4);
3300 s390_lr (code
, s390_r0
, ins
->sreg1
);
3301 s390_srda (code
, s390_r0
, 0, 32);
3302 s390_dr (code
, s390_r0
, ins
->sreg2
);
3303 s390_lr (code
, ins
->dreg
, s390_r1
);
3306 s390_lr (code
, s390_r0
, ins
->sreg1
);
3307 s390_srdl (code
, s390_r0
, 0, 32);
3308 s390_dlr (code
, s390_r0
, ins
->sreg2
);
3309 s390_lr (code
, ins
->dreg
, s390_r1
);
3312 if (s390_is_imm16 (ins
->inst_imm
)) {
3313 s390_lhi (code
, s390_r13
, ins
->inst_imm
);
3314 s390_lr (code
, s390_r0
, ins
->sreg1
);
3316 s390_basr (code
, s390_r13
, 0);
3318 s390_word (code
, ins
->inst_imm
);
3319 s390_lr (code
, s390_r0
, ins
->sreg1
);
3320 s390_l (code
, s390_r13
, 0, s390_r13
, 4);
3322 s390_srda (code
, s390_r0
, 0, 32);
3323 s390_dr (code
, s390_r0
, ins
->sreg2
);
3324 s390_lr (code
, ins
->dreg
, s390_r1
);
3327 s390_lr (code
, s390_r0
, ins
->sreg1
);
3328 s390_srda (code
, s390_r0
, 0, 32);
3329 s390_dr (code
, s390_r0
, ins
->sreg2
);
3330 s390_lr (code
, ins
->dreg
, s390_r0
);
3333 s390_lr (code
, s390_r0
, ins
->sreg1
);
3334 s390_srdl (code
, s390_r0
, 0, 32);
3335 s390_dlr (code
, s390_r0
, ins
->sreg2
);
3336 s390_lr (code
, ins
->dreg
, s390_r0
);
3339 if (s390_is_imm16 (ins
->inst_imm
)) {
3340 s390_lhi (code
, s390_r13
, ins
->inst_imm
);
3341 s390_lr (code
, s390_r0
, ins
->sreg1
);
3343 s390_basr (code
, s390_r13
, 0);
3345 s390_word (code
, ins
->inst_imm
);
3346 s390_lr (code
, s390_r0
, ins
->sreg1
);
3347 s390_l (code
, s390_r13
, 0, s390_r13
, 4);
3349 s390_srda (code
, s390_r0
, 0, 32);
3350 s390_dr (code
, s390_r0
, ins
->sreg2
);
3351 s390_lr (code
, ins
->dreg
, s390_r0
);
3354 if (ins
->sreg1
== ins
->dreg
) {
3355 s390_or (code
, ins
->dreg
, ins
->sreg2
);
3358 if (ins
->sreg2
== ins
->dreg
) {
3359 s390_or (code
, ins
->dreg
, ins
->sreg1
);
3362 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3363 s390_or (code
, ins
->dreg
, ins
->sreg2
);
3368 if (s390_is_imm16 (ins
->inst_imm
)) {
3369 s390_lhi (code
, s390_r0
, ins
->inst_imm
);
3370 if (ins
->dreg
!= ins
->sreg1
) {
3371 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3373 s390_or (code
, ins
->dreg
, s390_r0
);
3375 s390_bras (code
, s390_r13
, 4);
3376 s390_word (code
, ins
->inst_imm
);
3377 if (ins
->dreg
!= ins
->sreg1
) {
3378 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3380 s390_o (code
, ins
->dreg
, 0, s390_r13
, 0);
3384 if (ins
->sreg1
== ins
->dreg
) {
3385 s390_xr (code
, ins
->dreg
, ins
->sreg2
);
3388 if (ins
->sreg2
== ins
->dreg
) {
3389 s390_xr (code
, ins
->dreg
, ins
->sreg1
);
3392 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3393 s390_xr (code
, ins
->dreg
, ins
->sreg2
);
3398 if (s390_is_imm16 (ins
->inst_imm
)) {
3399 s390_lhi (code
, s390_r0
, ins
->inst_imm
);
3400 if (ins
->dreg
!= ins
->sreg1
) {
3401 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3403 s390_xr (code
, ins
->dreg
, s390_r0
);
3405 s390_basr (code
, s390_r13
, 0);
3407 s390_word (code
, ins
->inst_imm
);
3408 if (ins
->dreg
!= ins
->sreg1
) {
3409 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3411 s390_x (code
, ins
->dreg
, 0, s390_r13
, 4);
3415 if (ins
->sreg1
!= ins
->dreg
) {
3416 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3418 s390_sll (code
, ins
->dreg
, ins
->sreg2
, 0);
3421 if (ins
->sreg1
!= ins
->dreg
) {
3422 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3424 s390_sll (code
, ins
->dreg
, 0, (ins
->inst_imm
& 0x1f));
3427 if (ins
->sreg1
!= ins
->dreg
) {
3428 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3430 s390_sra (code
, ins
->dreg
, ins
->sreg2
, 0);
3433 if (ins
->sreg1
!= ins
->dreg
) {
3434 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3436 s390_sra (code
, ins
->dreg
, 0, (ins
->inst_imm
& 0x1f));
3439 if (ins
->sreg1
!= ins
->dreg
) {
3440 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3442 s390_srl (code
, ins
->dreg
, 0, (ins
->inst_imm
& 0x1f));
3445 if (ins
->sreg1
!= ins
->dreg
) {
3446 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3448 s390_srl (code
, ins
->dreg
, ins
->sreg2
, 0);
3451 if (ins
->sreg1
!= ins
->dreg
) {
3452 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3454 s390_lhi (code
, s390_r0
, -1);
3455 s390_xr (code
, ins
->dreg
, s390_r0
);
3458 s390_lcr (code
, ins
->dreg
, ins
->sreg1
);
3461 if (ins
->sreg1
== ins
->dreg
) {
3462 s390_msr (code
, ins
->dreg
, ins
->sreg2
);
3465 if (ins
->sreg2
== ins
->dreg
) {
3466 s390_msr (code
, ins
->dreg
, ins
->sreg1
);
3469 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3470 s390_msr (code
, ins
->dreg
, ins
->sreg2
);
3475 if (s390_is_imm16 (ins
->inst_imm
)) {
3476 s390_lhi (code
, s390_r13
, ins
->inst_imm
);
3478 s390_basr (code
, s390_r13
, 0);
3480 s390_word (code
, ins
->inst_imm
);
3481 if (ins
->dreg
!= ins
->sreg1
) {
3482 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3484 s390_l (code
, s390_r13
, 0, s390_r13
, 4);
3486 s390_msr (code
, ins
->dreg
, s390_r13
);
3489 s390_lhi (code
, s390_r0
, 0);
3490 s390_lr (code
, s390_r1
, ins
->sreg1
);
3491 s390_mr (code
, s390_r0
, ins
->sreg2
);
3492 s390_ltr (code
, s390_r0
, s390_r0
);
3493 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_NZ
, "OverflowException");
3494 s390_lr (code
, ins
->dreg
, s390_r1
);
3496 case CEE_MUL_OVF_UN
:
3497 s390_lhi (code
, s390_r0
, 0);
3498 s390_lr (code
, s390_r1
, ins
->sreg1
);
3499 s390_mlr (code
, s390_r0
, ins
->sreg2
);
3500 s390_ltr (code
, s390_r0
, s390_r0
);
3501 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_NZ
, "OverflowException");
3502 s390_lr (code
, ins
->dreg
, s390_r1
);
3505 s390_l (code
, s390_r0
, 0, ins
->sreg1
, 4);
3506 s390_lr (code
, s390_r14
, s390_r0
);
3507 s390_srda (code
, s390_r0
, 0, 32);
3508 s390_m (code
, s390_r0
, 0, ins
->sreg2
, 4);
3509 s390_srl (code
, s390_r14
, 0, 31);
3510 s390_a (code
, s390_r14
, 0, ins
->sreg1
, 0);
3511 s390_l (code
, s390_r13
, 0, ins
->sreg2
, 0);
3512 s390_srl (code
, s390_r13
, 0, 31);
3513 s390_ms (code
, s390_r13
, 0, ins
->sreg1
, 4);
3514 s390_ar (code
, s390_r14
, s390_r13
);
3515 s390_st (code
, s390_r14
, 0, ins
->dreg
, 0);
3516 s390_st (code
, s390_r1
, 0, ins
->dreg
, 4);
3520 if (s390_is_imm16(ins
->inst_c0
)) {
3521 s390_lhi (code
, ins
->dreg
, ins
->inst_c0
);
3523 s390_basr (code
, s390_r13
, 0);
3525 s390_word (code
, ins
->inst_c0
);
3526 s390_l (code
, ins
->dreg
, 0, s390_r13
, 4);
3530 s390_basr (code
, s390_r13
, 0);
3532 mono_add_patch_info (cfg
, code
- cfg
->native_code
,
3533 (MonoJumpInfoType
)ins
->inst_i1
, ins
->inst_p0
);
3534 s390_word (code
, 0);
3535 s390_l (code
,ins
->dreg
, 0, s390_r13
, 4);
3541 if (ins
->dreg
!= ins
->sreg1
) {
3542 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3546 int saved
= ins
->sreg1
;
3547 if (ins
->sreg1
== s390_r2
) {
3548 s390_lr (code
, s390_r0
, ins
->sreg1
);
3551 if (ins
->sreg2
!= s390_r2
)
3552 s390_lr (code
, s390_r2
, ins
->sreg2
);
3553 if (saved
!= s390_r3
)
3554 s390_lr (code
, s390_r3
, saved
);
3559 if (ins
->dreg
!= ins
->sreg1
) {
3560 s390_ldr (code
, ins
->dreg
, ins
->sreg1
);
3563 case OP_FCONV_TO_R4
:
3564 s390_ledbr (code
, ins
->dreg
, ins
->sreg1
);
3567 g_assert_not_reached ();
3570 /* ensure ins->sreg1 is not NULL */
3571 s390_icm (code
, s390_r0
, 15, ins
->sreg1
, 0);
3578 call
= (MonoCallInst
*)ins
;
3579 if (ins
->flags
& MONO_INST_HAS_METHOD
)
3580 mono_add_patch_info (cfg
, offset
, MONO_PATCH_INFO_METHOD
, call
->method
);
3582 mono_add_patch_info (cfg
, offset
, MONO_PATCH_INFO_ABS
, call
->fptr
);
3583 s390_brasl (code
, s390_r14
, 0);
3588 case OP_VOIDCALL_REG
:
3590 s390_lr (code
, s390_r1
, ins
->sreg1
);
3591 s390_basr (code
, s390_r14
, s390_r1
);
3593 case OP_FCALL_MEMBASE
:
3594 case OP_LCALL_MEMBASE
:
3595 case OP_VCALL_MEMBASE
:
3596 case OP_VOIDCALL_MEMBASE
:
3597 case OP_CALL_MEMBASE
:
3598 s390_l (code
, s390_r1
, 0, ins
->sreg1
, ins
->inst_offset
);
3599 s390_basr (code
, s390_r14
, s390_r1
);
3602 g_assert_not_reached ();
3605 s390_lr (code
, s390_r1
, ins
->sreg1
);
3606 s390_ahi (code
, s390_r1
, 14);
3607 s390_srl (code
, s390_r1
, 0, 3);
3608 s390_sll (code
, s390_r1
, 0, 3);
3609 s390_l (code
, s390_r13
, 0, STK_BASE
, 0);
3610 s390_lcr (code
, s390_r1
, s390_r1
);
3611 s390_la (code
, STK_BASE
, STK_BASE
, s390_r1
, 0);
3612 s390_st (code
, s390_r13
, 0, STK_BASE
, 0);
3613 s390_la (code
, ins
->dreg
, 0, STK_BASE
, S390_MINIMAL_STACK_SIZE
+7);
3614 s390_srl (code
, ins
->dreg
, 0, 3);
3615 s390_sll (code
, ins
->dreg
, 0, 3);
3618 s390_br (code
, s390_r14
);
3621 s390_lr (code
, s390_r2
, ins
->sreg1
);
3622 mono_add_patch_info (cfg
, code
-cfg
->native_code
, MONO_PATCH_INFO_INTERNAL_METHOD
,
3623 (gpointer
)"mono_arch_throw_exception");
3624 s390_brasl (code
, s390_r14
, 0);
3627 case OP_START_HANDLER
:
3628 s390_lr (code
, s390_r0
, s390_r14
);
3629 s390_st (code
, s390_r0
, 0, ins
->inst_left
->inst_basereg
, ins
->inst_left
->inst_offset
);
3632 if (ins
->sreg1
!= s390_r2
)
3633 s390_lr (code
, s390_r2
, ins
->sreg1
);
3634 s390_l (code
, STK_BASE
, 0, STK_BASE
, 0);
3635 s390_lm (code
, s390_r6
, s390_r14
, STK_BASE
, S390_REG_SAVE_OFFSET
);
3636 s390_br (code
, s390_r14
);
3638 case CEE_ENDFINALLY
:
3639 s390_l (code
, s390_r14
, 0, ins
->inst_left
->inst_basereg
, ins
->inst_left
->inst_offset
);
3640 s390_br (code
, s390_r14
);
3642 case OP_CALL_HANDLER
:
3643 mono_add_patch_info (cfg
, code
-cfg
->native_code
,
3644 MONO_PATCH_INFO_BB
, ins
->inst_target_bb
);
3645 s390_brasl (code
, s390_r14
, 0);
3648 ins
->inst_c0
= code
- cfg
->native_code
;
3651 EMIT_UNCOND_BRANCH(ins
);
3654 s390_br (code
, ins
->sreg1
);
3657 s390_lhi (code
, ins
->dreg
, 1);
3659 s390_lhi (code
, ins
->dreg
, 0);
3662 s390_lhi (code
, ins
->dreg
, 1);
3664 s390_lhi (code
, ins
->dreg
, 0);
3667 s390_lhi (code
, ins
->dreg
, 1);
3669 s390_lhi (code
, ins
->dreg
, 0);
3672 s390_lhi (code
, ins
->dreg
, 1);
3674 s390_lhi (code
, ins
->dreg
, 0);
3677 s390_lhi (code
, ins
->dreg
, 1);
3679 s390_lhi (code
, ins
->dreg
, 0);
3681 case OP_COND_EXC_EQ
:
3682 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_EQ
, ins
->inst_p1
);
3684 case OP_COND_EXC_NE_UN
:
3685 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_NE
, ins
->inst_p1
);
3687 case OP_COND_EXC_LT
:
3688 case OP_COND_EXC_LT_UN
:
3689 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_LT
, ins
->inst_p1
);
3691 case OP_COND_EXC_GT
:
3692 case OP_COND_EXC_GT_UN
:
3693 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_GT
, ins
->inst_p1
);
3695 case OP_COND_EXC_GE
:
3696 case OP_COND_EXC_GE_UN
:
3697 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_GE
, ins
->inst_p1
);
3699 case OP_COND_EXC_LE
:
3700 case OP_COND_EXC_LE_UN
:
3701 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_LE
, ins
->inst_p1
);
3703 case OP_COND_EXC_OV
:
3704 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_OV
, ins
->inst_p1
);
3706 case OP_COND_EXC_NO
:
3707 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_NO
, ins
->inst_p1
);
3710 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_CY
, ins
->inst_p1
);
3712 case OP_COND_EXC_NC
:
3713 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_NC
, ins
->inst_p1
);
3716 EMIT_COND_BRANCH (ins
, S390_CC_EQ
);
3719 EMIT_COND_BRANCH (ins
, S390_CC_NE
);
3723 EMIT_COND_BRANCH (ins
, S390_CC_LT
);
3727 EMIT_COND_BRANCH (ins
, S390_CC_GT
);
3731 EMIT_COND_BRANCH (ins
, S390_CC_GE
);
3735 EMIT_COND_BRANCH (ins
, S390_CC_LE
);
3738 /* floating point opcodes */
3740 if (*((float *) ins
->inst_p0
) == 0) {
3741 s390_lzdr (code
, ins
->dreg
);
3743 s390_basr (code
, s390_r13
, 0);
3745 s390_word (code
, ins
->inst_p0
);
3746 s390_l (code
, s390_r13
, 0, s390_r13
, 4);
3747 s390_ld (code
, ins
->dreg
, 0, s390_r13
, 0);
3751 if (*((float *) ins
->inst_p0
) == 0) {
3752 s390_lzer (code
, ins
->dreg
);
3754 s390_basr (code
, s390_r13
, 0);
3756 s390_word (code
, ins
->inst_p0
);
3757 s390_l (code
, s390_r13
, 0, s390_r13
, 4);
3758 s390_le (code
, ins
->dreg
, 0, s390_r13
, 0);
3759 s390_ldebr(code
, ins
->dreg
, ins
->dreg
);
3762 case OP_STORER8_MEMBASE_REG
:
3763 if (s390_is_uimm12(ins
->inst_offset
)) {
3764 s390_std (code
, ins
->sreg1
, 0, ins
->inst_destbasereg
, ins
->inst_offset
);
3766 s390_basr (code
, s390_r13
, 0);
3768 s390_word (code
, ins
->inst_offset
);
3769 s390_l (code
, s390_r13
, 0, s390_r13
, 4);
3770 s390_std (code
, ins
->sreg1
, s390_r13
, ins
->inst_destbasereg
, 0);
3773 case OP_LOADR8_MEMBASE
:
3774 if (s390_is_uimm12(ins
->inst_offset
)) {
3775 s390_ld (code
, ins
->dreg
, 0, ins
->inst_basereg
, ins
->inst_offset
);
3777 s390_basr (code
, s390_r13
, 0);
3779 s390_word (code
, ins
->inst_offset
);
3780 s390_l (code
, s390_r13
, 0, s390_r13
, 4);
3781 s390_ld (code
, ins
->dreg
, s390_r13
, ins
->inst_basereg
, 0);
3784 case OP_STORER4_MEMBASE_REG
:
3785 if (s390_is_uimm12(ins
->inst_offset
)) {
3786 s390_ledbr(code
, s390_f0
, ins
->sreg1
);
3787 s390_ste (code
, s390_f0
, 0, ins
->inst_destbasereg
, ins
->inst_offset
);
3789 s390_basr (code
, s390_r13
, 0);
3791 s390_word (code
, ins
->inst_offset
);
3792 s390_l (code
, s390_r13
, 0, s390_r13
, 4);
3793 s390_ledbr(code
, s390_f0
, ins
->sreg1
);
3794 s390_ste (code
, s390_f0
, s390_r13
, ins
->inst_destbasereg
, 0);
3797 case OP_LOADR4_MEMBASE
:
3798 if (s390_is_uimm12(ins
->inst_offset
)) {
3799 s390_le (code
, ins
->dreg
, 0, ins
->inst_basereg
, ins
->inst_offset
);
3801 s390_basr (code
, s390_r13
, 0);
3803 s390_word (code
, ins
->inst_offset
);
3804 s390_l (code
, s390_r13
, 0, s390_r13
, 4);
3805 s390_le (code
, ins
->dreg
, s390_r13
, ins
->inst_basereg
, 0);
3807 s390_ldebr (code
, ins
->dreg
, ins
->dreg
);
3810 s390_cdfbr (code
, ins
->dreg
, ins
->sreg1
);
3811 s390_ltr (code
, ins
->sreg1
, ins
->sreg1
);
3812 s390_jnl (code
, 12);
3813 s390_basr (code
, s390_r13
, 0);
3815 s390_word (code
, 0x41f00000);
3816 s390_word (code
, 0);
3817 s390_adb (code
, ins
->dreg
, 0, s390_r13
, 4);
3820 s390_cefbr (code
, ins
->dreg
, ins
->sreg1
);
3823 s390_cdfbr (code
, ins
->dreg
, ins
->sreg1
);
3825 case OP_FCONV_TO_I1
:
3826 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 1, TRUE
);
3828 case OP_FCONV_TO_U1
:
3829 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 1, FALSE
);
3831 case OP_FCONV_TO_I2
:
3832 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 2, TRUE
);
3834 case OP_FCONV_TO_U2
:
3835 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 2, FALSE
);
3837 case OP_FCONV_TO_I4
:
3839 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 4, TRUE
);
3841 case OP_FCONV_TO_U4
:
3843 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 4, FALSE
);
3845 case OP_FCONV_TO_I8
:
3846 case OP_FCONV_TO_U8
:
3847 g_assert_not_reached ();
3848 /* Implemented as helper calls */
3850 case OP_LCONV_TO_R_UN
:
3851 g_assert_not_reached ();
3852 /* Implemented as helper calls */
3854 case OP_LCONV_TO_OVF_I
: {
3855 /* Valid ints: 0xffffffff:8000000 to 00000000:0x7f000000 */
3857 s390_ltr (code
, ins
->sreg2
, ins
->sreg2
);
3858 s390_jnl (code
, 0); CODEPTR(code
, o
[0]);
3859 s390_ltr (code
, ins
->sreg1
, ins
->sreg1
);
3860 s390_jnl (code
, 0); CODEPTR(code
, o
[1]);
3861 s390_lhi (code
, s390_r13
, -1);
3862 s390_cr (code
, ins
->sreg1
, s390_r13
);
3863 s390_jnz (code
, 0); CODEPTR(code
, o
[2]);
3864 if (ins
->dreg
!= ins
->sreg2
)
3865 s390_lr (code
, ins
->dreg
, ins
->sreg2
);
3866 s390_j (code
, 0); CODEPTR(code
, o
[3]);
3867 PTRSLOT(code
, o
[0]);
3868 s390_jz (code
, 0); CODEPTR(code
, o
[4]);
3869 PTRSLOT(code
, o
[1]);
3870 PTRSLOT(code
, o
[2]);
3871 mono_add_patch_info (cfg
, code
- cfg
->native_code
,
3872 MONO_PATCH_INFO_EXC
, "OverflowException");
3873 s390_brasl (code
, s390_r14
, 0);
3874 PTRSLOT(code
, o
[3]);
3875 PTRSLOT(code
, o
[4]);
3879 s390_sqdbr (code
, ins
->dreg
, ins
->sreg1
);
3882 if (ins
->dreg
== ins
->sreg1
)
3883 s390_adbr (code
, ins
->dreg
, ins
->sreg2
);
3885 if (ins
->dreg
== ins
->sreg2
)
3886 s390_adbr (code
, ins
->dreg
, ins
->sreg1
);
3888 s390_ldr (code
, ins
->dreg
, ins
->sreg1
);
3889 s390_adbr (code
, ins
->dreg
, ins
->sreg2
);
3894 if (ins
->dreg
== ins
->sreg1
)
3895 s390_sdbr (code
, ins
->dreg
, ins
->sreg2
);
3897 s390_ldr (code
, ins
->dreg
, ins
->sreg1
);
3898 s390_sdbr (code
, ins
->dreg
, ins
->sreg2
);
3902 if (ins
->dreg
== ins
->sreg1
)
3903 s390_mdbr (code
, ins
->dreg
, ins
->sreg2
);
3905 if (ins
->dreg
== ins
->sreg2
)
3906 s390_mdbr (code
, ins
->dreg
, ins
->sreg1
);
3908 s390_ldr (code
, ins
->dreg
, ins
->sreg1
);
3909 s390_mdbr (code
, ins
->dreg
, ins
->sreg2
);
3914 if (ins
->dreg
== ins
->sreg1
)
3915 s390_ddbr (code
, ins
->dreg
, ins
->sreg2
);
3917 s390_ldr (code
, ins
->dreg
, ins
->sreg1
);
3918 s390_ddbr (code
, ins
->dreg
, ins
->sreg2
);
3922 s390_lcdbr (code
, ins
->dreg
, ins
->sreg1
);
3925 if (ins
->dreg
!= ins
->sreg1
) {
3926 s390_ldr (code
, ins
->dreg
, ins
->sreg1
);
3928 s390_didbr (code
, ins
->dreg
, ins
->sreg2
, 5, s390_f15
);
3931 s390_cdbr (code
, ins
->sreg1
, ins
->sreg2
);
3934 s390_cdbr (code
, ins
->sreg1
, ins
->sreg2
);
3935 s390_lhi (code
, ins
->dreg
, 1);
3937 s390_lhi (code
, ins
->dreg
, 0);
3940 s390_cdbr (code
, ins
->sreg1
, ins
->sreg2
);
3941 s390_lhi (code
, ins
->dreg
, 1);
3943 s390_lhi (code
, ins
->dreg
, 0);
3946 s390_cdbr (code
, ins
->sreg1
, ins
->sreg2
);
3947 s390_lhi (code
, ins
->dreg
, 1);
3949 s390_lhi (code
, ins
->dreg
, 0);
3952 s390_cdbr (code
, ins
->sreg1
, ins
->sreg2
);
3953 s390_lhi (code
, ins
->dreg
, 1);
3955 s390_lhi (code
, ins
->dreg
, 0);
3958 s390_cdbr (code
, ins
->sreg1
, ins
->sreg2
);
3959 s390_lhi (code
, ins
->dreg
, 1);
3961 s390_lhi (code
, ins
->dreg
, 0);
3964 EMIT_COND_BRANCH (ins
, S390_CC_EQ
|S390_CC_OV
);
3967 EMIT_COND_BRANCH (ins
, S390_CC_NE
|S390_CC_OV
);
3970 EMIT_COND_BRANCH (ins
, S390_CC_LT
);
3973 EMIT_COND_BRANCH (ins
, S390_CC_LT
|S390_CC_OV
);
3976 EMIT_COND_BRANCH (ins
, S390_CC_GT
);
3979 EMIT_COND_BRANCH (ins
, S390_CC_GT
|S390_CC_OV
);
3982 EMIT_COND_BRANCH (ins
, S390_CC_GE
);
3985 EMIT_COND_BRANCH (ins
, S390_CC_GE
|S390_CC_OV
);
3988 EMIT_COND_BRANCH (ins
, S390_CC_LE
);
3991 EMIT_COND_BRANCH (ins
, S390_CC_LE
|S390_CC_OV
);
3993 case CEE_CKFINITE
: {
3995 s390_lhi (code
, s390_r13
, 0xfc0);
3996 s390_tcdb (code
, ins
->sreg1
, 0, s390_r13
, 0);
3997 s390_jz (code
, 0); CODEPTR(code
, o
);
3998 mono_add_patch_info (cfg
, code
- cfg
->native_code
+ 2,
3999 MONO_PATCH_INFO_EXC
, "ArithmeticException");
4000 s390_brasl (code
, s390_r14
,0);
4005 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins
->opcode
), __FUNCTION__
);
4006 g_assert_not_reached ();
4009 if ((cfg
->opt
& MONO_OPT_BRANCH
) && ((code
- cfg
->native_code
- offset
) > max_len
)) {
4010 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
4011 mono_inst_name (ins
->opcode
), max_len
, code
- cfg
->native_code
- offset
);
4012 g_assert_not_reached ();
4018 last_offset
= offset
;
4023 cfg
->code_len
= code
- cfg
->native_code
;
4026 /*========================= End of Function ========================*/
4028 /*------------------------------------------------------------------*/
4030 /* Name - mono_arch_register_lowlevel_calls */
4032 /* Function - Register routines to help with --trace operation. */
4034 /*------------------------------------------------------------------*/
4037 mono_arch_register_lowlevel_calls (void)
4039 mono_register_jit_icall (enter_method
, "mono_enter_method", NULL
, TRUE
);
4040 mono_register_jit_icall (leave_method
, "mono_leave_method", NULL
, TRUE
);
4043 /*========================= End of Function ========================*/
4045 /*------------------------------------------------------------------*/
4047 /* Name - mono_arch_patch_code */
4049 /* Function - Process the patch data created during the */
4050 /* instruction build process. This resolves jumps, */
4051 /* calls, variables etc. */
4053 /*------------------------------------------------------------------*/
4056 mono_arch_patch_code (MonoMethod
*method
, MonoDomain
*domain
, guint8
*code
, MonoJumpInfo
*ji
, gboolean run_cctors
)
4058 MonoJumpInfo
*patch_info
;
4060 for (patch_info
= ji
; patch_info
; patch_info
= patch_info
->next
) {
4061 unsigned char *ip
= patch_info
->ip
.i
+ code
;
4064 switch (patch_info
->type
) {
4065 case MONO_PATCH_INFO_BB
:
4066 target
= S390_RELATIVE((patch_info
->data
.bb
->native_offset
+code
),
4068 ip
+= 2; /* Skip over op-code */
4070 case MONO_PATCH_INFO_ABS
:
4071 target
= S390_RELATIVE(patch_info
->data
.target
, ip
);
4072 ip
+= 2; /* Skip over op-code */
4074 case MONO_PATCH_INFO_LABEL
:
4075 target
= S390_RELATIVE((patch_info
->data
.inst
->inst_c0
+code
),ip
);
4076 ip
+= 2; /* Skip over op-code */
4078 case MONO_PATCH_INFO_IP
:
4081 case MONO_PATCH_INFO_METHOD_REL
:
4082 g_assert_not_reached ();
4083 *((gpointer
*)(ip
)) = code
+ patch_info
->data
.offset
;
4085 case MONO_PATCH_INFO_INTERNAL_METHOD
: {
4086 MonoJitICallInfo
*mi
= mono_find_jit_icall_by_name (patch_info
->data
.name
);
4088 g_warning ("unknown MONO_PATCH_INFO_INTERNAL_METHOD %s", patch_info
->data
.name
);
4089 g_assert_not_reached ();
4091 target
= S390_RELATIVE(mono_icall_get_wrapper (mi
), ip
);
4092 ip
+= 2; /* Skip over op-code */
4095 case MONO_PATCH_INFO_METHOD_JUMP
:
4096 g_assert_not_reached ();
4098 case MONO_PATCH_INFO_METHOD
:
4099 if (patch_info
->data
.method
== method
) {
4100 target
= S390_RELATIVE(code
, ip
);
4102 /* get the trampoline to the method from the domain */
4103 target
= S390_RELATIVE(mono_arch_create_jit_trampoline (patch_info
->data
.method
), ip
);
4104 target
= mono_arch_create_jit_trampoline(patch_info
->data
.method
);
4105 target
= S390_RELATIVE(target
, ip
);
4107 ip
+= 2; /* Skip over op-code */
4109 case MONO_PATCH_INFO_SWITCH
: {
4110 gpointer
*table
= (gpointer
*)patch_info
->data
.target
;
4112 /*------------------------------------------------------*/
4113 /* ip is pointing at the basr r13,0/j +4 instruction */
4114 /* the vtable value follows this (i.e. ip+6) */
4115 /*------------------------------------------------------*/
4116 *((gconstpointer
*)(ip
+6)) = table
;
4118 for (i
= 0; i
< patch_info
->table_size
; i
++) {
4119 table
[i
] = (int)patch_info
->data
.table
[i
] + code
;
4123 case MONO_PATCH_INFO_METHODCONST
:
4124 case MONO_PATCH_INFO_CLASS
:
4125 case MONO_PATCH_INFO_IMAGE
:
4126 case MONO_PATCH_INFO_FIELD
:
4127 target
= S390_RELATIVE(patch_info
->data
.target
, ip
);
4129 case MONO_PATCH_INFO_R4
:
4130 case MONO_PATCH_INFO_R8
:
4131 g_assert_not_reached ();
4132 *((gconstpointer
*)(ip
+ 2)) = patch_info
->data
.target
;
4134 case MONO_PATCH_INFO_IID
:
4135 mono_class_init (patch_info
->data
.klass
);
4136 target
= S390_RELATIVE(patch_info
->data
.klass
->interface_id
, ip
);
4138 case MONO_PATCH_INFO_VTABLE
:
4139 target
= S390_RELATIVE(mono_class_vtable (domain
, patch_info
->data
.klass
),ip
);
4142 case MONO_PATCH_INFO_CLASS_INIT
:
4143 target
= S390_RELATIVE(mono_create_class_init_trampoline (mono_class_vtable (domain
, patch_info
->data
.klass
)), ip
);
4146 case MONO_PATCH_INFO_SFLDA
: {
4147 MonoVTable
*vtable
= mono_class_vtable (domain
, patch_info
->data
.field
->parent
);
4148 if (!vtable
->initialized
&& !(vtable
->klass
->flags
& TYPE_ATTRIBUTE_BEFORE_FIELD_INIT
) && mono_class_needs_cctor_run (vtable
->klass
, method
))
4149 /* Done by the generated code */
4153 mono_runtime_class_init (vtable
);
4155 target
= S390_RELATIVE((char*)vtable
->data
+ patch_info
->data
.field
->offset
, ip
);
4159 case MONO_PATCH_INFO_EXC_NAME
:
4160 *((gconstpointer
*)(ip
)) = patch_info
->data
.name
;
4162 case MONO_PATCH_INFO_LDSTR
:
4163 target
= mono_ldstr (domain
, patch_info
->data
.token
->image
,
4164 mono_metadata_token_index (patch_info
->data
.token
->token
));
4166 case MONO_PATCH_INFO_TYPE_FROM_HANDLE
: {
4168 MonoClass
*handle_class
;
4170 handle
= mono_ldtoken (patch_info
->data
.token
->image
,
4171 patch_info
->data
.token
->token
,
4172 &handle_class
, NULL
);
4173 mono_class_init (handle_class
);
4174 mono_class_init (mono_class_from_mono_type (handle
));
4179 case MONO_PATCH_INFO_LDTOKEN
: {
4181 MonoClass
*handle_class
;
4183 handle
= mono_ldtoken (patch_info
->data
.token
->image
,
4184 patch_info
->data
.token
->token
,
4185 &handle_class
, NULL
);
4186 mono_class_init (handle_class
);
4191 case MONO_PATCH_INFO_EXC
:
4192 /* everything is dealt with at epilog output time */
4195 g_assert_not_reached ();
4197 s390_patch (ip
, target
);
4201 /*========================= End of Function ========================*/
4203 /*------------------------------------------------------------------*/
4205 /* Name - mono_arch_max_epilog_size */
4207 /* Function - Determine the maximum size of the epilog code. */
4209 /*------------------------------------------------------------------*/
4212 mono_arch_max_epilog_size (MonoCompile
*cfg
)
4214 int max_epilog_size
= 96;
4215 MonoJumpInfo
*patch_info
;
4217 if (cfg
->method
->save_lmf
)
4218 max_epilog_size
+= 128;
4220 if (mono_jit_trace_calls
!= NULL
)
4221 max_epilog_size
+= 128;
4223 if (cfg
->prof_options
& MONO_PROFILE_ENTER_LEAVE
)
4224 max_epilog_size
+= 128;
4226 /* count the number of exception infos */
4228 for (patch_info
= cfg
->patch_info
; patch_info
; patch_info
= patch_info
->next
) {
4229 if (patch_info
->type
== MONO_PATCH_INFO_EXC
)
4230 max_epilog_size
+= 26;
4233 return max_epilog_size
;
4236 /*========================= End of Function ========================*/
4238 /*------------------------------------------------------------------*/
4240 /* Name - mono_arch_emit_prolog */
4242 /* Function - Create the instruction sequence for a function */
4245 /*------------------------------------------------------------------*/
4248 mono_arch_emit_prolog (MonoCompile
*cfg
)
4250 MonoMethod
*method
= cfg
->method
;
4252 MonoMethodSignature
*sig
;
4254 int alloc_size
, pos
, max_offset
, i
, lmfOffset
;
4260 if (mono_jit_trace_calls
!= NULL
&& mono_trace_eval (method
))
4263 cfg
->code_size
= 256;
4264 cfg
->native_code
= code
= g_malloc (cfg
->code_size
);
4266 s390_stm (code
, s390_r6
, s390_r14
, STK_BASE
, S390_REG_SAVE_OFFSET
);
4268 if (cfg
->flags
& MONO_CFG_HAS_ALLOCA
) {
4269 cfg
->used_int_regs
|= 1 << 11;
4272 alloc_size
= cfg
->stack_offset
;
4274 // alloc_size += S390_TRACE_STACK_SIZE;
4276 /* reserve room to save return value */
4280 // alloc_size += pos;
4282 // if (method->save_lmf)
4283 // alloc_size += sizeof(MonoLMF);
4285 // alloc_size = S390_ALIGN(alloc_size, S390_STACK_ALIGNMENT);
4287 cfg
->stack_usage
= alloc_size
;
4288 s390_lr (code
, s390_r11
, STK_BASE
);
4289 if (s390_is_imm16 (-alloc_size
)) {
4290 s390_ahi (code
, STK_BASE
, -alloc_size
);
4292 int stackSize
= alloc_size
;
4293 while (stackSize
> 32767) {
4294 s390_ahi (code
, STK_BASE
, -32767);
4297 s390_ahi (code
, STK_BASE
, -stackSize
);
4299 s390_st (code
, s390_r11
, 0, STK_BASE
, 0);
4301 if (cfg
->flags
& MONO_CFG_HAS_ALLOCA
)
4302 s390_lr (code
, s390_r11
, STK_BASE
);
4304 /* compute max_offset in order to use short forward jumps
4305 * we always do it on s390 because the immediate displacement
4306 * for jumps is too small
4309 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
) {
4310 MonoInst
*ins
= bb
->code
;
4311 bb
->max_offset
= max_offset
;
4313 if (cfg
->prof_options
& MONO_PROFILE_COVERAGE
)
4317 max_offset
+= ((guint8
*)ins_spec
[ins
->opcode
])[MONO_INST_LEN
];
4322 /* load arguments allocated to register from the stack */
4323 sig
= method
->signature
;
4326 cinfo
= calculate_sizes (sig
, &sz
, sig
->pinvoke
);
4328 if (cinfo
->struct_ret
) {
4329 ArgInfo
*ainfo
= &cinfo
->ret
;
4331 inst
->unused
= ainfo
->vtsize
;
4332 s390_st (code
, ainfo
->reg
, 0, inst
->inst_basereg
, inst
->inst_offset
);
4335 for (i
= 0; i
< sig
->param_count
+ sig
->hasthis
; ++i
) {
4336 ArgInfo
*ainfo
= cinfo
->args
+ i
;
4337 inst
= cfg
->varinfo
[pos
];
4339 if (inst
->opcode
== OP_REGVAR
) {
4340 if (ainfo
->regtype
== RegTypeGeneral
)
4341 s390_lr (code
, inst
->dreg
, ainfo
->reg
);
4342 else if (ainfo
->regtype
== RegTypeFP
) {
4343 if (ainfo
->size
== 4) {
4344 s390_ledbr (code
, inst
->dreg
, ainfo
->reg
);
4346 s390_ldr (code
, inst
->dreg
, ainfo
->reg
);
4349 else if (ainfo
->regtype
== RegTypeBase
) {
4350 s390_lr (code
, s390_r13
, STK_BASE
);
4351 s390_ahi (code
, s390_r13
, alloc_size
);
4352 s390_l (code
, inst
->dreg
, 0, s390_r13
, ainfo
->offset
);
4354 g_assert_not_reached ();
4356 if (cfg
->verbose_level
> 2)
4357 g_print ("Argument %d assigned to register %s\n",
4358 pos
, mono_arch_regname (inst
->dreg
));
4360 if (ainfo
->regtype
== RegTypeGeneral
) {
4361 if (!((ainfo
->reg
>= 2) && (ainfo
->reg
<= 6)))
4362 g_assert_not_reached();
4363 switch (ainfo
->size
) {
4365 s390_stc (code
, ainfo
->reg
, 0, inst
->inst_basereg
, inst
->inst_offset
);
4368 s390_sth (code
, ainfo
->reg
, 0, inst
->inst_basereg
, inst
->inst_offset
);
4371 s390_stm (code
, ainfo
->reg
, ainfo
->reg
+ 1,
4372 inst
->inst_basereg
, inst
->inst_offset
);
4375 s390_st (code
, ainfo
->reg
, 0, inst
->inst_basereg
, inst
->inst_offset
);
4377 } else if (ainfo
->regtype
== RegTypeBase
) {
4378 } else if (ainfo
->regtype
== RegTypeFP
) {
4379 if (ainfo
->size
== 8)
4380 s390_std (code
, ainfo
->reg
, 0, inst
->inst_basereg
, inst
->inst_offset
);
4381 else if (ainfo
->size
== 4)
4382 s390_ste (code
, ainfo
->reg
, 0, inst
->inst_basereg
, inst
->inst_offset
);
4384 g_assert_not_reached ();
4385 } else if (ainfo
->regtype
== RegTypeStructByVal
) {
4386 int doffset
= inst
->inst_offset
;
4388 if (ainfo
->reg
!= STK_BASE
)
4392 s390_lr (code
, s390_r13
, STK_BASE
);
4393 s390_ahi (code
, s390_r13
, alloc_size
);
4395 switch (ainfo
->size
) {
4397 if (ainfo
->reg
== STK_BASE
)
4398 s390_ic (code
, reg
, 0, s390_r13
, ainfo
->offset
+3);
4399 s390_stc (code
, reg
, 0, inst
->inst_basereg
, doffset
);
4402 if (ainfo
->reg
== STK_BASE
)
4403 s390_lh (code
, reg
, 0, s390_r13
, ainfo
->offset
+2);
4404 s390_sth (code
, reg
, 0, inst
->inst_basereg
, doffset
);
4407 if (ainfo
->reg
== STK_BASE
)
4408 s390_l (code
, reg
, 0, s390_r13
, ainfo
->offset
);
4409 s390_st (code
, reg
, 0, inst
->inst_basereg
, doffset
);
4412 if (ainfo
->reg
== STK_BASE
)
4413 s390_lm (code
, s390_r0
, s390_r1
, s390_r13
, ainfo
->offset
);
4414 s390_stm (code
, reg
, reg
+1, inst
->inst_basereg
, doffset
);
4417 } else if (ainfo
->regtype
== RegTypeStructByAddr
) {
4418 code
= emit_memcpy (code
, ainfo
->vtsize
,
4419 inst
->inst_basereg
, inst
->inst_offset
, ainfo
->reg
, 0);
4421 g_assert_not_reached ();
4426 if (method
->save_lmf
) {
4427 /*---------------------------------------------------------------*/
4428 /* Preserve the parameter registers while we fix up the lmf */
4429 /*---------------------------------------------------------------*/
4430 s390_lr (code
, s390_r7
, s390_r2
);
4431 s390_lr (code
, s390_r8
, s390_r3
);
4432 s390_lr (code
, s390_r9
, s390_r4
);
4433 s390_lr (code
, s390_r10
, s390_r5
);
4435 mono_add_patch_info (cfg
, code
- cfg
->native_code
,
4436 MONO_PATCH_INFO_INTERNAL_METHOD
,
4437 (gpointer
)"mono_get_lmf_addr");
4438 /*---------------------------------------------------------------*/
4439 /* On return from this call r2 have the address of the &lmf */
4440 /*---------------------------------------------------------------*/
4441 s390_brasl (code
, s390_r14
, 0);
4443 /*---------------------------------------------------------------*/
4444 /* we build the MonoLMF structure on the stack - see mini-s390.h */
4445 /*---------------------------------------------------------------*/
4446 lmfOffset
= alloc_size
- sizeof(MonoLMF
);
4448 s390_lr (code
, s390_r13
, cfg
->frame_reg
);
4449 s390_ahi (code
, s390_r13
, lmfOffset
);
4451 /*---------------------------------------------------------------*/
4452 /* Set lmf.lmf_addr = jit_tls->lmf */
4453 /*---------------------------------------------------------------*/
4454 s390_st (code
, s390_r2
, 0, s390_r13
, G_STRUCT_OFFSET(MonoLMF
, lmf_addr
));
4456 /*---------------------------------------------------------------*/
4457 /* Get current lmf */
4458 /*---------------------------------------------------------------*/
4459 s390_l (code
, s390_r0
, 0, s390_r2
, 0);
4461 /*---------------------------------------------------------------*/
4462 /* Set our lmf as the current lmf */
4463 /*---------------------------------------------------------------*/
4464 s390_st (code
, s390_r13
, 0, s390_r2
, 0);
4466 /*---------------------------------------------------------------*/
4467 /* Have our lmf.previous_lmf point to the last lmf */
4468 /*---------------------------------------------------------------*/
4469 s390_st (code
, s390_r0
, 0, s390_r13
, G_STRUCT_OFFSET(MonoLMF
, previous_lmf
));
4471 /*---------------------------------------------------------------*/
4472 /* save method info */
4473 /*---------------------------------------------------------------*/
4474 s390_basr (code
, s390_r1
, 0);
4476 s390_word (code
, method
);
4477 s390_l (code
, s390_r1
, 0, s390_r1
, 4);
4478 s390_st (code
, s390_r1
, 0, s390_r13
, G_STRUCT_OFFSET(MonoLMF
, method
));
4480 /*---------------------------------------------------------------*/
4481 /* save the current IP */
4482 /*---------------------------------------------------------------*/
4483 s390_lr (code
, s390_r1
, cfg
->frame_reg
);
4484 // s390_ahi (code, s390_r1, alloc_size);
4485 s390_st (code
, s390_r1
, 0, s390_r13
, G_STRUCT_OFFSET(MonoLMF
, ebp
));
4486 s390_l (code
, s390_r1
, 0, s390_r1
, S390_RET_ADDR_OFFSET
);
4487 s390_la (code
, s390_r1
, 0, s390_r1
, 0);
4488 s390_st (code
, s390_r1
, 0, s390_r13
, G_STRUCT_OFFSET(MonoLMF
, eip
));
4490 /*---------------------------------------------------------------*/
4491 /* Save general and floating point registers */
4492 /*---------------------------------------------------------------*/
4493 s390_stm (code
, s390_r2
, s390_r6
, s390_r13
, G_STRUCT_OFFSET(MonoLMF
, gregs
[2]));
4494 for (i
= 0; i
< 16; i
++) {
4495 s390_std (code
, i
, 0, s390_r13
, G_STRUCT_OFFSET(MonoLMF
, fregs
[i
]));
4498 /*---------------------------------------------------------------*/
4499 /* Restore the parameter registers now that we've set up the lmf */
4500 /*---------------------------------------------------------------*/
4501 s390_lr (code
, s390_r2
, s390_r7
);
4502 s390_lr (code
, s390_r3
, s390_r8
);
4503 s390_lr (code
, s390_r4
, s390_r9
);
4504 s390_lr (code
, s390_r5
, s390_r10
);
4508 code
= mono_arch_instrument_prolog (cfg
, enter_method
, code
, TRUE
);
4510 cfg
->code_len
= code
- cfg
->native_code
;
4516 /*========================= End of Function ========================*/
4518 /*------------------------------------------------------------------*/
4520 /* Name - mono_arch_emit_epilog */
4522 /* Function - Emit the instructions for a function epilog. */
4524 /*------------------------------------------------------------------*/
4527 mono_arch_emit_epilog (MonoCompile
*cfg
)
4529 MonoJumpInfo
*patch_info
;
4530 MonoMethod
*method
= cfg
->method
;
4531 MonoMethodSignature
*sig
= method
->signature
;
4533 int i
, lmfOffset
, tracing
= 0;
4536 code
= cfg
->native_code
+ cfg
->code_len
;
4538 if (mono_jit_trace_calls
!= NULL
&& mono_trace_eval (method
)) {
4539 code
= mono_arch_instrument_epilog (cfg
, leave_method
, code
, TRUE
);
4543 if (method
->save_lmf
) {
4544 s390_lr (code
, s390_r13
, cfg
->frame_reg
);
4546 lmfOffset
= cfg
->stack_usage
- sizeof(MonoLMF
);
4548 /*-------------------------------------------------*/
4550 /*-------------------------------------------------*/
4551 s390_ahi (code
, s390_r13
, lmfOffset
);
4553 /*-------------------------------------------------*/
4554 /* r6 = &jit_tls->lmf */
4555 /*-------------------------------------------------*/
4556 s390_l (code
, s390_r6
, 0, s390_r13
, G_STRUCT_OFFSET(MonoLMF
, lmf_addr
));
4558 /*-------------------------------------------------*/
4559 /* r0 = lmf.previous_lmf */
4560 /*-------------------------------------------------*/
4561 s390_l (code
, s390_r0
, 0, s390_r13
, G_STRUCT_OFFSET(MonoLMF
, previous_lmf
));
4563 /*-------------------------------------------------*/
4564 /* jit_tls->lmf = previous_lmf */
4565 /*-------------------------------------------------*/
4566 s390_l (code
, s390_r13
, 0, s390_r6
, 0);
4567 s390_st (code
, s390_r0
, 0, s390_r6
, 0);
4570 if (cfg
->frame_reg
!= STK_BASE
)
4571 s390_lr (code
, STK_BASE
, cfg
->frame_reg
);
4573 s390_ahi (code
, STK_BASE
, cfg
->stack_usage
);
4574 s390_lm (code
, s390_r6
, s390_r14
, STK_BASE
, S390_REG_SAVE_OFFSET
);
4575 s390_br (code
, s390_r14
);
4577 /* add code to raise exceptions */
4578 for (patch_info
= cfg
->patch_info
; patch_info
; patch_info
= patch_info
->next
) {
4579 switch (patch_info
->type
) {
4580 case MONO_PATCH_INFO_EXC
: {
4581 /*-----------------------------------------------------*/
4582 /* Patch the branch in epilog to come here */
4583 /*-----------------------------------------------------*/
4584 s390_patch (patch_info
->ip
.i
+cfg
->native_code
+2,
4585 S390_RELATIVE(code
,patch_info
->ip
.i
+cfg
->native_code
));
4586 /*-----------------------------------------------------*/
4587 /* Patch the parameter passed to the handler */
4588 /*-----------------------------------------------------*/
4589 s390_basr (code
, s390_r13
, 0);
4591 mono_add_patch_info (cfg
, code
- cfg
->native_code
,
4592 MONO_PATCH_INFO_EXC_NAME
,
4593 patch_info
->data
.target
);
4594 s390_word (code
, 0);
4595 /*-----------------------------------------------------*/
4596 /* Load the return address and the parameter register */
4597 /*-----------------------------------------------------*/
4598 s390_larl (code
, s390_r14
, S390_RELATIVE((patch_info
->ip
.i
+
4599 cfg
->native_code
+ 8), code
));
4600 s390_l (code
, s390_r2
, 0, s390_r13
, 4);
4601 /*-----------------------------------------------------*/
4602 /* Reuse the current patch to set the jump */
4603 /*-----------------------------------------------------*/
4604 patch_info
->type
= MONO_PATCH_INFO_INTERNAL_METHOD
;
4605 patch_info
->data
.name
= "mono_arch_throw_exception_by_name";
4606 patch_info
->ip
.i
= code
- cfg
->native_code
;
4607 s390_jcl (code
, S390_CC_UN
, 0);
4616 cfg
->code_len
= code
- cfg
->native_code
;
4618 g_assert (cfg
->code_len
< cfg
->code_size
);
4622 /*========================= End of Function ========================*/
4624 /*------------------------------------------------------------------*/
4626 /* Name - mono_arch_setup_jit_tls_data */
4628 /* Function - Setup the JIT's Thread Level Specific Data. */
4630 /*------------------------------------------------------------------*/
4633 mono_arch_setup_jit_tls_data (MonoJitTlsData
*tls
)
4637 /*========================= End of Function ========================*/
4639 /*------------------------------------------------------------------*/
4641 /* Name - mono_arch_free_jit_tls_data */
4643 /* Function - Free tls data. */
4645 /*------------------------------------------------------------------*/
4648 mono_arch_free_jit_tls_data (MonoJitTlsData
*tls
)
4652 /*========================= End of Function ========================*/
4654 /*------------------------------------------------------------------*/
4656 /* Name - mono_arch_emit_this_vret_args */
4660 /*------------------------------------------------------------------*/
4663 mono_arch_emit_this_vret_args (MonoCompile
*cfg
, MonoCallInst
*inst
, int this_reg
, int this_type
, int vt_reg
)
4665 int this_dreg
= s390_r2
;
4668 this_dreg
= s390_r3
;
4670 /* add the this argument */
4671 if (this_reg
!= -1) {
4673 MONO_INST_NEW (cfg
, this, OP_SETREG
);
4674 this->type
= this_type
;
4675 this->sreg1
= this_reg
;
4676 this->dreg
= this_dreg
;
4677 mono_bblock_add_inst (cfg
->cbb
, this);
4682 MONO_INST_NEW (cfg
, vtarg
, OP_SETREG
);
4683 vtarg
->type
= STACK_MP
;
4684 vtarg
->sreg1
= vt_reg
;
4685 vtarg
->dreg
= s390_r2
;
4686 mono_bblock_add_inst (cfg
->cbb
, vtarg
);
4690 /*========================= End of Function ========================*/
4692 /*------------------------------------------------------------------*/
4694 /* Name - mono_arch_get_opcode_for_method */
4696 /* Function - Check for opcodes we can handle directly in */
4699 /*------------------------------------------------------------------*/
4702 mono_arch_get_opcode_for_method (MonoCompile
*cfg
, MonoMethod
*cmethod
, MonoMethodSignature
*fsig
, MonoInst
**args
)
4704 if (cmethod
->klass
== mono_defaults
.math_class
) {
4705 if (strcmp (cmethod
->name
, "Sqrt") == 0)
4711 /*========================= End of Function ========================*/
4713 /*------------------------------------------------------------------*/
4715 /* Name - mono_arch_print_tree */
4717 /* Function - Print platform-specific opcode details. */
4719 /* Returns - 1 - opcode details have been printed */
4720 /* 0 - opcode details have not been printed */
4722 /*------------------------------------------------------------------*/
4725 mono_arch_print_tree (MonoInst
*tree
, int arity
)
4729 switch (tree
->opcode
) {
4730 case OP_S390_LOADARG
:
4731 case OP_S390_ARGPTR
:
4732 case OP_S390_STKARG
:
4733 printf ("[0x%x(%s)]", tree
->inst_offset
,
4734 mono_arch_regname (tree
->inst_basereg
));
4743 /*========================= End of Function ========================*/
4745 /*------------------------------------------------------------------*/
4747 /* Name - mono_arch_regalloc_cost */
4749 /* Function - Determine the cost, in the number of memory */
4750 /* references, of the action of allocating the var- */
4751 /* iable VMV into a register during global register */
4754 /* Returns - Cost */
4756 /*------------------------------------------------------------------*/
4759 mono_arch_regalloc_cost (MonoCompile
*cfg
, MonoMethodVar
*vmv
)
4765 /*========================= End of Function ========================*/