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\n", __builtin_return_address (1));
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
);
1323 curinst
= m
->locals_start
;
1324 for (iVar
= curinst
; iVar
< m
->num_varinfo
; ++iVar
) {
1325 inst
= m
->varinfo
[iVar
];
1326 if (inst
->opcode
== OP_REGVAR
)
1329 /* inst->unused indicates native sized value types, this is used by the
1330 * pinvoke wrappers when they call functions returning structure */
1331 if (inst
->unused
&& MONO_TYPE_ISSTRUCT (inst
->inst_vtype
))
1332 size
= mono_class_native_size (inst
->inst_vtype
->data
.klass
, &align
);
1334 size
= mono_type_size (inst
->inst_vtype
, &align
);
1336 offset
= S390_ALIGN(offset
, align
);
1337 inst
->inst_offset
= offset
;
1338 inst
->opcode
= OP_REGOFFSET
;
1339 inst
->inst_basereg
= frame_reg
;
1341 //DEBUG (g_print("allocating local %d to %d\n", iVar, inst->inst_offset));
1349 eArg
= sig
->param_count
+ sArg
;
1351 for (iParm
= sArg
; iParm
< eArg
; ++iParm
) {
1352 inst
= m
->varinfo
[curinst
];
1353 if (inst
->opcode
!= OP_REGVAR
) {
1354 if (cinfo
->args
[iParm
].regtype
== RegTypeStructByVal
) {
1355 if (cinfo
->args
[iParm
].vtsize
!= 0) {
1356 inst
->opcode
= OP_S390_LOADARG
;
1357 inst
->inst_basereg
= frame_reg
;
1358 size
= sizeof(long);
1359 offset
= S390_ALIGN(offset
, size
);
1360 inst
->inst_offset
= offset
;
1362 inst
->opcode
= OP_S390_ARGPTR
;
1363 inst
->inst_basereg
= frame_reg
;
1364 size
= cinfo
->args
[iParm
].size
;
1365 offset
= S390_ALIGN(offset
, size
);
1366 inst
->inst_offset
= offset
;
1369 if (cinfo
->args
[iParm
].reg
!= STK_BASE
) {
1370 inst
->opcode
= OP_REGOFFSET
;
1371 inst
->inst_basereg
= frame_reg
;
1372 size
= (cinfo
->args
[iParm
].size
< 8
1374 : sizeof(long long));
1375 offset
= S390_ALIGN(offset
, size
);
1376 inst
->inst_offset
= offset
;
1378 inst
->opcode
= OP_S390_STKARG
;
1379 inst
->inst_basereg
= frame_reg
;
1380 size
= (cinfo
->args
[iParm
].size
< 4
1381 ? 4 - cinfo
->args
[iParm
].size
1383 inst
->inst_offset
= cinfo
->args
[iParm
].offset
+
1385 // inst->unused = stackOffset;
1387 size
= sizeof(long);
1395 /*------------------------------------------------------*/
1396 /* Allow space for the trace method stack area if needed*/
1397 /*------------------------------------------------------*/
1398 if (mono_jit_trace_calls
!= NULL
&& mono_trace_eval (m
))
1399 offset
+= S390_TRACE_STACK_SIZE
;
1401 /*------------------------------------------------------*/
1402 /* Reserve space to save LMF and caller saved registers */
1403 /*------------------------------------------------------*/
1404 if (m
->method
->save_lmf
)
1405 offset
+= sizeof (MonoLMF
);
1407 /*------------------------------------------------------*/
1408 /* align the offset */
1409 /*------------------------------------------------------*/
1410 m
->stack_offset
= S390_ALIGN(offset
, S390_STACK_ALIGNMENT
);
1414 /*========================= End of Function ========================*/
1416 /*------------------------------------------------------------------*/
1418 /* Name - mono_arch_call_opcode */
1420 /* Function - Take the arguments and generate the arch-specific */
1421 /* instructions to properly call the function. This */
1422 /* includes pushing, moving argments to the correct */
1425 /* Note - FIXME: We need an alignment solution for */
1426 /* enter_method and mono_arch_call_opcode, currently */
1427 /* alignment in mono_arch_call_opcode is computed */
1428 /* without arch_get_argument_info. */
1430 /*------------------------------------------------------------------*/
1433 mono_arch_call_opcode (MonoCompile
*cfg
, MonoBasicBlock
* bb
, MonoCallInst
*call
, int is_virtual
) {
1435 MonoMethodSignature
*sig
;
1436 int i
, n
, lParamArea
;
1441 sig
= call
->signature
;
1442 n
= sig
->param_count
+ sig
->hasthis
;
1444 cinfo
= calculate_sizes (sig
, &sz
, sig
->pinvoke
);
1445 if (cinfo
->struct_ret
)
1446 call
->used_iregs
|= 1 << cinfo
->struct_ret
;
1448 for (i
= 0; i
< n
; ++i
) {
1449 ainfo
= cinfo
->args
+ i
;
1450 if (is_virtual
&& i
== 0) {
1451 /* the argument will be attached to the call instrucion */
1452 in
= call
->args
[i
];
1453 call
->used_iregs
|= 1 << ainfo
->reg
;
1455 MONO_INST_NEW (cfg
, arg
, OP_OUTARG
);
1456 in
= call
->args
[i
];
1457 arg
->cil_code
= in
->cil_code
;
1458 arg
->inst_left
= in
;
1459 arg
->type
= in
->type
;
1460 /* prepend, we'll need to reverse them later */
1461 arg
->next
= call
->out_args
;
1462 call
->out_args
= arg
;
1463 if (ainfo
->regtype
== RegTypeGeneral
) {
1464 arg
->unused
= ainfo
->reg
;
1465 call
->used_iregs
|= 1 << ainfo
->reg
;
1466 if (arg
->type
== STACK_I8
)
1467 call
->used_iregs
|= 1 << (ainfo
->reg
+ 1);
1468 } else if (ainfo
->regtype
== RegTypeStructByAddr
) {
1469 arg
->unused
= ainfo
->reg
;
1470 call
->used_iregs
|= 1 << ainfo
->reg
;
1471 } else if (ainfo
->regtype
== RegTypeStructByVal
) {
1472 if (ainfo
->reg
!= STK_BASE
) {
1473 switch (ainfo
->size
) {
1478 call
->used_iregs
|= 1 << ainfo
->reg
;
1481 call
->used_iregs
|= 1 << ainfo
->reg
;
1482 call
->used_iregs
|= 1 << (ainfo
->reg
+1);
1486 arg
->sreg2
= ainfo
->reg
;
1487 arg
->opcode
= OP_OUTARG_VT
;
1488 if (ainfo
->vtsize
!= 0)
1489 arg
->unused
= -ainfo
->vtsize
;
1491 arg
->unused
= ainfo
->size
;
1492 arg
->inst_imm
= ainfo
->offset
;
1493 arg
->sreg1
= ainfo
->offparm
;
1494 } else if (ainfo
->regtype
== RegTypeBase
) {
1495 arg
->opcode
= OP_OUTARG
;
1496 arg
->unused
= ainfo
->reg
| (ainfo
->size
<< 8);
1497 arg
->inst_imm
= ainfo
->offset
;
1498 } else if (ainfo
->regtype
== RegTypeFP
) {
1499 arg
->opcode
= OP_OUTARG_R8
;
1500 arg
->unused
= ainfo
->reg
;
1501 call
->used_fregs
|= 1 << ainfo
->reg
;
1502 if (ainfo
->size
== 4) {
1503 /* we reduce the precision */
1505 MONO_INST_NEW (cfg
, conv
, OP_FCONV_TO_R4
);
1506 conv
->inst_left
= arg
->inst_left
;
1507 arg
->inst_left
= conv
;
1510 g_assert_not_reached ();
1515 * Reverse the call->out_args list.
1518 MonoInst
*prev
= NULL
, *list
= call
->out_args
, *next
;
1525 call
->out_args
= prev
;
1527 call
->stack_usage
= cinfo
->stack_usage
;
1529 lParamArea
= cinfo
->stack_usage
- S390_MINIMAL_STACK_SIZE
;
1530 cfg
->param_area
= MAX (cfg
->param_area
, lParamArea
);
1531 cfg
->flags
|= MONO_CFG_HAS_CALLS
;
1532 /*----------------------------------------------------------*/
1533 /* should set more info in call, such as the stack space */
1534 /* used by the args that needs to be added back to esp */
1535 /*----------------------------------------------------------*/
1541 /*========================= End of Function ========================*/
1543 /*------------------------------------------------------------------*/
1545 /* Name - mono_arch_instrument_mem_needs */
1547 /* Function - Allow tracing to work with this interface (with */
1548 /* an optional argument). */
1550 /*------------------------------------------------------------------*/
1553 mono_arch_instrument_mem_needs (MonoMethod
*method
, int *stack
, int *code
)
1555 /* no stack room needed now (may be needed for FASTCALL-trace support) */
1557 /* split prolog-epilog requirements? */
1558 *code
= 50; /* max bytes needed: check this number */
1561 /*========================= End of Function ========================*/
1563 /*------------------------------------------------------------------*/
1565 /* Name - mono_arch_instrument_prolog */
1567 /* Function - Create an "instrumented" prolog. */
1569 /*------------------------------------------------------------------*/
1572 mono_arch_instrument_prolog (MonoCompile
*cfg
, void *func
, void *p
,
1573 gboolean enable_arguments
)
1579 parmOffset
= cfg
->stack_usage
- S390_TRACE_STACK_SIZE
;
1580 if (cfg
->method
->save_lmf
)
1581 parmOffset
-= sizeof(MonoLMF
);
1582 fpOffset
= parmOffset
+ (5*sizeof(gint32
));
1584 s390_stm (code
, s390_r2
, s390_r6
, STK_BASE
, parmOffset
);
1585 s390_std (code
, s390_f0
, 0, STK_BASE
, fpOffset
);
1586 s390_std (code
, s390_f1
, 0, STK_BASE
, fpOffset
+sizeof(gdouble
));
1587 s390_std (code
, s390_f2
, 0, STK_BASE
, fpOffset
+2*sizeof(gdouble
));
1588 s390_basr (code
, s390_r13
, 0);
1590 s390_word (code
, cfg
->method
);
1591 s390_word (code
, func
);
1592 s390_l (code
, s390_r2
, 0, s390_r13
, 4);
1593 s390_la (code
, s390_r3
, 0, STK_BASE
, parmOffset
);
1594 s390_lr (code
, s390_r4
, STK_BASE
);
1595 s390_ahi (code
, s390_r4
, cfg
->stack_usage
);
1596 s390_l (code
, s390_r1
, 0, s390_r13
, 8);
1597 s390_basr (code
, s390_r14
, s390_r1
);
1598 s390_ld (code
, s390_f2
, 0, STK_BASE
, fpOffset
+2*sizeof(gdouble
));
1599 s390_ld (code
, s390_f1
, 0, STK_BASE
, fpOffset
+sizeof(gdouble
));
1600 s390_ld (code
, s390_f0
, 0, STK_BASE
, fpOffset
);
1601 s390_lm (code
, s390_r2
, s390_r6
, STK_BASE
, parmOffset
);
1606 /*========================= End of Function ========================*/
1608 /*------------------------------------------------------------------*/
1610 /* Name - mono_arch_instrument_epilog */
1612 /* Function - Create an epilog that will handle the returned */
1613 /* values used in instrumentation. */
1615 /*------------------------------------------------------------------*/
1618 mono_arch_instrument_epilog (MonoCompile
*cfg
, void *func
, void *p
, gboolean enable_arguments
)
1621 int save_mode
= SAVE_NONE
,
1623 MonoMethod
*method
= cfg
->method
;
1624 int rtype
= method
->signature
->ret
->type
;
1626 saveOffset
= cfg
->stack_usage
- S390_TRACE_STACK_SIZE
;
1627 if (method
->save_lmf
)
1628 saveOffset
-= sizeof(MonoLMF
);
1632 case MONO_TYPE_VOID
:
1633 /* special case string .ctor icall */
1634 if (strcmp (".ctor", method
->name
) && method
->klass
== mono_defaults
.string_class
)
1635 save_mode
= SAVE_ONE
;
1637 save_mode
= SAVE_NONE
;
1641 save_mode
= SAVE_TWO
;
1645 save_mode
= SAVE_FP
;
1647 case MONO_TYPE_VALUETYPE
:
1648 if (method
->signature
->ret
->data
.klass
->enumtype
) {
1649 rtype
= method
->signature
->ret
->data
.klass
->enum_basetype
->type
;
1652 save_mode
= SAVE_STRUCT
;
1655 save_mode
= SAVE_ONE
;
1659 switch (save_mode
) {
1661 s390_stm (code
, s390_r2
, s390_r3
, cfg
->frame_reg
, saveOffset
);
1662 if (enable_arguments
) {
1663 s390_lr (code
, s390_r4
, s390_r3
);
1664 s390_lr (code
, s390_r3
, s390_r2
);
1668 s390_st (code
, s390_r2
, 0, cfg
->frame_reg
, saveOffset
);
1669 if (enable_arguments
) {
1670 s390_lr (code
, s390_r3
, s390_r2
);
1674 s390_std (code
, s390_f0
, 0, cfg
->frame_reg
, saveOffset
);
1675 if (enable_arguments
) {
1676 /* FIXME: what reg? */
1677 s390_ldr (code
, s390_f2
, s390_f0
);
1678 s390_lm (code
, s390_r3
, s390_r4
, cfg
->frame_reg
, saveOffset
);
1682 s390_st (code
, s390_r2
, 0, cfg
->frame_reg
, saveOffset
);
1683 if (enable_arguments
) {
1684 s390_l (code
, s390_r3
, 0, cfg
->frame_reg
,
1685 S390_MINIMAL_STACK_SIZE
+cfg
->param_area
);
1693 s390_basr (code
, s390_r13
, 0);
1695 s390_word (code
, cfg
->method
);
1696 s390_word (code
, func
);
1697 s390_l (code
, s390_r2
, 0, s390_r13
, 4);
1698 s390_l (code
, s390_r1
, 0, s390_r13
, 8);
1699 s390_basr (code
, s390_r14
, s390_r1
);
1701 switch (save_mode
) {
1703 s390_lm (code
, s390_r2
, s390_r3
, cfg
->frame_reg
, saveOffset
);
1706 s390_l (code
, s390_r2
, 0, cfg
->frame_reg
, saveOffset
);
1709 s390_ld (code
, s390_f0
, 0, cfg
->frame_reg
, saveOffset
);
1712 s390_l (code
, s390_r2
, 0, cfg
->frame_reg
, saveOffset
);
1722 /*========================= End of Function ========================*/
1724 /*------------------------------------------------------------------*/
1726 /* Name - peephole_pass */
1728 /* Function - Form a peephole pass at the code looking for */
1729 /* simple optimizations. */
1731 /*------------------------------------------------------------------*/
1734 peephole_pass (MonoCompile
*cfg
, MonoBasicBlock
*bb
)
1736 MonoInst
*ins
, *last_ins
= NULL
;
1741 switch (ins
->opcode
) {
1743 /* remove unnecessary multiplication with 1 */
1744 if (ins
->inst_imm
== 1) {
1745 if (ins
->dreg
!= ins
->sreg1
) {
1746 ins
->opcode
= OP_MOVE
;
1748 last_ins
->next
= ins
->next
;
1754 case OP_LOAD_MEMBASE
:
1755 case OP_LOADI4_MEMBASE
:
1757 * OP_STORE_MEMBASE_REG reg, offset(basereg)
1758 * OP_LOAD_MEMBASE offset(basereg), reg
1760 if (last_ins
&& (last_ins
->opcode
== OP_STOREI4_MEMBASE_REG
1761 || last_ins
->opcode
== OP_STORE_MEMBASE_REG
) &&
1762 ins
->inst_basereg
== last_ins
->inst_destbasereg
&&
1763 ins
->inst_offset
== last_ins
->inst_offset
) {
1764 if (ins
->dreg
== last_ins
->sreg1
) {
1765 last_ins
->next
= ins
->next
;
1769 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1770 ins
->opcode
= OP_MOVE
;
1771 ins
->sreg1
= last_ins
->sreg1
;
1775 * Note: reg1 must be different from the basereg in the second load
1776 * OP_LOAD_MEMBASE offset(basereg), reg1
1777 * OP_LOAD_MEMBASE offset(basereg), reg2
1779 * OP_LOAD_MEMBASE offset(basereg), reg1
1780 * OP_MOVE reg1, reg2
1782 } if (last_ins
&& (last_ins
->opcode
== OP_LOADI4_MEMBASE
1783 || last_ins
->opcode
== OP_LOAD_MEMBASE
) &&
1784 ins
->inst_basereg
!= last_ins
->dreg
&&
1785 ins
->inst_basereg
== last_ins
->inst_basereg
&&
1786 ins
->inst_offset
== last_ins
->inst_offset
) {
1788 if (ins
->dreg
== last_ins
->dreg
) {
1789 last_ins
->next
= ins
->next
;
1793 ins
->opcode
= OP_MOVE
;
1794 ins
->sreg1
= last_ins
->dreg
;
1797 //g_assert_not_reached ();
1801 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1802 * OP_LOAD_MEMBASE offset(basereg), reg
1804 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1805 * OP_ICONST reg, imm
1807 } else if (last_ins
&& (last_ins
->opcode
== OP_STOREI4_MEMBASE_IMM
1808 || last_ins
->opcode
== OP_STORE_MEMBASE_IMM
) &&
1809 ins
->inst_basereg
== last_ins
->inst_destbasereg
&&
1810 ins
->inst_offset
== last_ins
->inst_offset
) {
1811 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1812 ins
->opcode
= OP_ICONST
;
1813 ins
->inst_c0
= last_ins
->inst_imm
;
1814 g_assert_not_reached (); // check this rule
1818 case OP_LOADU1_MEMBASE
:
1819 case OP_LOADI1_MEMBASE
:
1820 if (last_ins
&& (last_ins
->opcode
== OP_STOREI1_MEMBASE_REG
) &&
1821 ins
->inst_basereg
== last_ins
->inst_destbasereg
&&
1822 ins
->inst_offset
== last_ins
->inst_offset
) {
1823 if (ins
->dreg
== last_ins
->sreg1
) {
1824 last_ins
->next
= ins
->next
;
1828 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1829 ins
->opcode
= OP_MOVE
;
1830 ins
->sreg1
= last_ins
->sreg1
;
1834 case OP_LOADU2_MEMBASE
:
1835 case OP_LOADI2_MEMBASE
:
1836 if (last_ins
&& (last_ins
->opcode
== OP_STOREI2_MEMBASE_REG
) &&
1837 ins
->inst_basereg
== last_ins
->inst_destbasereg
&&
1838 ins
->inst_offset
== last_ins
->inst_offset
) {
1839 if (ins
->dreg
== last_ins
->sreg1
) {
1840 last_ins
->next
= ins
->next
;
1844 ins
->opcode
= OP_MOVE
;
1845 ins
->sreg1
= last_ins
->sreg1
;
1855 if (ins
->dreg
== ins
->sreg1
) {
1857 last_ins
->next
= ins
->next
;
1862 * OP_MOVE sreg, dreg
1863 * OP_MOVE dreg, sreg
1865 if (last_ins
&& last_ins
->opcode
== OP_MOVE
&&
1866 ins
->sreg1
== last_ins
->dreg
&&
1867 ins
->dreg
== last_ins
->sreg1
) {
1868 last_ins
->next
= ins
->next
;
1877 bb
->last_ins
= last_ins
;
1880 /*========================= End of Function ========================*/
1882 /*------------------------------------------------------------------*/
1884 /* Name - mono_spillvar_offset */
1886 /* Function - Returns the offset used by spillvar. It allocates */
1887 /* a new spill variable if necessary. */
1889 /*------------------------------------------------------------------*/
1892 mono_spillvar_offset (MonoCompile
*cfg
, int spillvar
)
1894 MonoSpillInfo
**si
, *info
;
1897 si
= &cfg
->spill_info
;
1899 while (i
<= spillvar
) {
1902 *si
= info
= mono_mempool_alloc (cfg
->mempool
, sizeof (MonoSpillInfo
));
1904 info
->offset
= cfg
->stack_offset
;
1905 cfg
->stack_offset
+= sizeof (gpointer
);
1909 return (*si
)->offset
;
1915 g_assert_not_reached ();
1919 /*========================= End of Function ========================*/
1921 /*------------------------------------------------------------------*/
1923 /* Name - mono_spillvar_offset_float */
1927 /*------------------------------------------------------------------*/
1930 mono_spillvar_offset_float (MonoCompile
*cfg
, int spillvar
)
1932 MonoSpillInfo
**si
, *info
;
1935 si
= &cfg
->spill_info_float
;
1937 while (i
<= spillvar
) {
1940 *si
= info
= mono_mempool_alloc (cfg
->mempool
, sizeof (MonoSpillInfo
));
1942 cfg
->stack_offset
= S390_ALIGN(cfg
->stack_offset
, S390_STACK_ALIGNMENT
);
1943 info
->offset
= cfg
->stack_offset
;
1944 cfg
->stack_offset
+= sizeof (double);
1948 return (*si
)->offset
;
1954 g_assert_not_reached ();
1958 /*========================= End of Function ========================*/
1960 /*------------------------------------------------------------------*/
1962 /* Name - print_ins */
1964 /* Function - Decode and print the instruction for tracing. */
1966 /*------------------------------------------------------------------*/
1969 print_ins (int i
, MonoInst
*ins
)
1971 const char *spec
= ins_spec
[ins
->opcode
];
1972 g_print ("\t%-2d %s", i
, mono_inst_name (ins
->opcode
));
1973 if (spec
[MONO_INST_DEST
]) {
1974 if (ins
->dreg
>= MONO_MAX_IREGS
)
1975 g_print (" R%d <-", ins
->dreg
);
1977 g_print (" %s <-", mono_arch_regname (ins
->dreg
));
1979 if (spec
[MONO_INST_SRC1
]) {
1980 if (ins
->sreg1
>= MONO_MAX_IREGS
)
1981 g_print (" R%d", ins
->sreg1
);
1983 g_print (" %s", mono_arch_regname (ins
->sreg1
));
1985 if (spec
[MONO_INST_SRC2
]) {
1986 if (ins
->sreg2
>= MONO_MAX_IREGS
)
1987 g_print (" R%d", ins
->sreg2
);
1989 g_print (" %s", mono_arch_regname (ins
->sreg2
));
1991 if (spec
[MONO_INST_CLOB
])
1992 g_print (" clobbers: %c", spec
[MONO_INST_CLOB
]);
1996 /*========================= End of Function ========================*/
1998 /*------------------------------------------------------------------*/
2000 /* Name - print_regtrack. */
2004 /*------------------------------------------------------------------*/
2007 print_regtrack (RegTrack
*t
, int num
)
2013 for (i
= 0; i
< num
; ++i
) {
2016 if (i
>= MONO_MAX_IREGS
) {
2017 g_snprintf (buf
, sizeof(buf
), "R%d", i
);
2020 r
= mono_arch_regname (i
);
2021 g_print ("liveness: %s [%d - %d]\n", r
, t
[i
].born_in
, t
[i
].last_use
);
2025 /*========================= End of Function ========================*/
2027 /*------------------------------------------------------------------*/
2029 /* Name - inst_list_prepend */
2031 /* Function - Prepend an instruction to the list. */
2033 /*------------------------------------------------------------------*/
2035 static inline InstList
*
2036 inst_list_prepend (MonoMemPool
*pool
, InstList
*list
, MonoInst
*data
)
2038 InstList
*item
= mono_mempool_alloc (pool
, sizeof (InstList
));
2047 /*========================= End of Function ========================*/
2049 /*------------------------------------------------------------------*/
2051 /* Name - get_register_force_spilling */
2053 /* Function - Force the spilling of the variable in the */
2054 /* symbolic register 'reg'. */
2056 /*------------------------------------------------------------------*/
2059 get_register_force_spilling (MonoCompile
*cfg
, InstList
*item
, MonoInst
*ins
, int reg
)
2064 sel
= cfg
->rs
->iassign
[reg
];
2066 spill
= ++cfg
->spill_count
;
2067 cfg
->rs
->iassign
[i
] = -spill
- 1;
2068 mono_regstate_free_int (cfg
->rs
, sel
);
2069 /*----------------------------------------------------------*/
2070 /* we need to create a spill var and insert a load to sel */
2071 /* after the current instruction */
2072 /*----------------------------------------------------------*/
2073 MONO_INST_NEW (cfg
, load
, OP_LOAD_MEMBASE
);
2075 load
->inst_basereg
= cfg
->frame_reg
;
2076 load
->inst_offset
= mono_spillvar_offset (cfg
, spill
);
2078 while (ins
->next
!= item
->prev
->data
)
2081 load
->next
= ins
->next
;
2083 DEBUG (g_print ("SPILLED LOAD (%d at 0x%08x(%%sp)) R%d (freed %s)\n",
2084 spill
, load
->inst_offset
, i
, mono_arch_regname (sel
)));
2085 i
= mono_regstate_alloc_int (cfg
->rs
, 1 << sel
);
2086 g_assert (i
== sel
);
2091 /*========================= End of Function ========================*/
2093 /*------------------------------------------------------------------*/
2095 /* Name - get_register_spilling */
2099 /*------------------------------------------------------------------*/
2102 get_register_spilling (MonoCompile
*cfg
, InstList
*item
, MonoInst
*ins
, guint32 regmask
, int reg
)
2107 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
));
2108 /* exclude the registers in the current instruction */
2109 if (reg
!= ins
->sreg1
&&
2110 (reg_is_freeable (ins
->sreg1
) ||
2111 (ins
->sreg1
>= MONO_MAX_IREGS
&&
2112 cfg
->rs
->iassign
[ins
->sreg1
] >= 0))) {
2113 if (ins
->sreg1
>= MONO_MAX_IREGS
)
2114 regmask
&= ~ (1 << cfg
->rs
->iassign
[ins
->sreg1
]);
2116 regmask
&= ~ (1 << ins
->sreg1
);
2117 DEBUG (g_print ("excluding sreg1 %s\n", mono_arch_regname (ins
->sreg1
)));
2119 if (reg
!= ins
->sreg2
&&
2120 (reg_is_freeable (ins
->sreg2
) ||
2121 (ins
->sreg2
>= MONO_MAX_IREGS
&&
2122 cfg
->rs
->iassign
[ins
->sreg2
] >= 0))) {
2123 if (ins
->sreg2
>= MONO_MAX_IREGS
)
2124 regmask
&= ~ (1 << cfg
->rs
->iassign
[ins
->sreg2
]);
2126 regmask
&= ~ (1 << ins
->sreg2
);
2127 DEBUG (g_print ("excluding sreg2 %s %d\n", mono_arch_regname (ins
->sreg2
), ins
->sreg2
));
2129 if (reg
!= ins
->dreg
&& reg_is_freeable (ins
->dreg
)) {
2130 regmask
&= ~ (1 << ins
->dreg
);
2131 DEBUG (g_print ("excluding dreg %s\n", mono_arch_regname (ins
->dreg
)));
2134 DEBUG (g_print ("available regmask: 0x%08x\n", regmask
));
2135 g_assert (regmask
); /* need at least a register we can free */
2137 /* we should track prev_use and spill the register that's farther */
2138 for (i
= 0; i
< MONO_MAX_IREGS
; ++i
) {
2139 if (regmask
& (1 << i
)) {
2141 DEBUG (g_print ("selected register %s has assignment %d\n", mono_arch_regname (sel
), cfg
->rs
->iassign
[sel
]));
2145 i
= cfg
->rs
->isymbolic
[sel
];
2146 spill
= ++cfg
->spill_count
;
2147 cfg
->rs
->iassign
[i
] = -spill
- 1;
2148 mono_regstate_free_int (cfg
->rs
, sel
);
2149 /* we need to create a spill var and insert a load to sel after the current instruction */
2150 MONO_INST_NEW (cfg
, load
, OP_LOAD_MEMBASE
);
2152 load
->inst_basereg
= cfg
->frame_reg
;
2153 load
->inst_offset
= mono_spillvar_offset (cfg
, spill
);
2155 while (ins
->next
!= item
->prev
->data
)
2158 load
->next
= ins
->next
;
2160 DEBUG (g_print ("SPILLED LOAD (%d at 0x%08x(%%sp)) R%d (freed %s)\n", spill
, load
->inst_offset
, i
, mono_arch_regname (sel
)));
2161 i
= mono_regstate_alloc_int (cfg
->rs
, 1 << sel
);
2162 g_assert (i
== sel
);
2167 /*========================= End of Function ========================*/
2169 /*------------------------------------------------------------------*/
2171 /* Name - get_float_register_spilling */
2175 /*------------------------------------------------------------------*/
2178 get_float_register_spilling (MonoCompile
*cfg
, InstList
*item
, MonoInst
*ins
, guint32 regmask
, int reg
)
2183 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
));
2184 /* exclude the registers in the current instruction */
2185 if (reg
!= ins
->sreg1
&&
2186 (freg_is_freeable (ins
->sreg1
) ||
2187 (ins
->sreg1
>= MONO_MAX_FREGS
&&
2188 cfg
->rs
->fassign
[ins
->sreg1
] >= 0))) {
2189 if (ins
->sreg1
>= MONO_MAX_FREGS
)
2190 regmask
&= ~ (1 << cfg
->rs
->fassign
[ins
->sreg1
]);
2192 regmask
&= ~ (1 << ins
->sreg1
);
2193 DEBUG (g_print ("excluding sreg1 %s\n", mono_arch_regname (ins
->sreg1
)));
2195 if (reg
!= ins
->sreg2
&&
2196 (freg_is_freeable (ins
->sreg2
) ||
2197 (ins
->sreg2
>= MONO_MAX_FREGS
&&
2198 cfg
->rs
->fassign
[ins
->sreg2
] >= 0))) {
2199 if (ins
->sreg2
>= MONO_MAX_FREGS
)
2200 regmask
&= ~ (1 << cfg
->rs
->fassign
[ins
->sreg2
]);
2202 regmask
&= ~ (1 << ins
->sreg2
);
2203 DEBUG (g_print ("excluding sreg2 %s %d\n", mono_arch_regname (ins
->sreg2
), ins
->sreg2
));
2205 if (reg
!= ins
->dreg
&& freg_is_freeable (ins
->dreg
)) {
2206 regmask
&= ~ (1 << ins
->dreg
);
2207 DEBUG (g_print ("excluding dreg %s\n", mono_arch_regname (ins
->dreg
)));
2210 DEBUG (g_print ("available regmask: 0x%08x\n", regmask
));
2211 g_assert (regmask
); /* need at least a register we can free */
2213 /* we should track prev_use and spill the register that's farther */
2214 for (i
= 0; i
< MONO_MAX_FREGS
; ++i
) {
2215 if (regmask
& (1 << i
)) {
2217 DEBUG (g_print ("selected register %s has assignment %d\n",
2218 mono_arch_regname (sel
), cfg
->rs
->fassign
[sel
]));
2222 i
= cfg
->rs
->fsymbolic
[sel
];
2223 spill
= ++cfg
->spill_count
;
2224 cfg
->rs
->fassign
[i
] = -spill
- 1;
2225 mono_regstate_free_float(cfg
->rs
, sel
);
2226 /* we need to create a spill var and insert a load to sel after the current instruction */
2227 MONO_INST_NEW (cfg
, load
, OP_LOADR8_MEMBASE
);
2229 load
->inst_basereg
= cfg
->frame_reg
;
2230 load
->inst_offset
= mono_spillvar_offset_float (cfg
, spill
);
2232 while (ins
->next
!= item
->prev
->data
)
2235 load
->next
= ins
->next
;
2237 DEBUG (g_print ("SPILLED LOAD (%d at 0x%08x(%%sp)) R%d (freed %s)\n", spill
, load
->inst_offset
, i
, mono_arch_regname (sel
)));
2238 i
= mono_regstate_alloc_float (cfg
->rs
, 1 << sel
);
2239 g_assert (i
== sel
);
2244 /*========================= End of Function ========================*/
2246 /*------------------------------------------------------------------*/
2248 /* Name - create_copy_ins */
2250 /* Function - Create an instruction to copy from reg to reg. */
2252 /*------------------------------------------------------------------*/
2255 create_copy_ins (MonoCompile
*cfg
, int dest
, int src
, MonoInst
*ins
)
2258 MONO_INST_NEW (cfg
, copy
, OP_MOVE
);
2262 copy
->next
= ins
->next
;
2265 DEBUG (g_print ("\tforced copy from %s to %s\n",
2266 mono_arch_regname (src
), mono_arch_regname (dest
)));
2270 /*========================= End of Function ========================*/
2272 /*------------------------------------------------------------------*/
2274 /* Name - create_copy_ins_float */
2276 /* Function - Create an instruction to copy from float reg to */
2279 /*------------------------------------------------------------------*/
2282 create_copy_ins_float (MonoCompile
*cfg
, int dest
, int src
, MonoInst
*ins
)
2285 MONO_INST_NEW (cfg
, copy
, OP_FMOVE
);
2289 copy
->next
= ins
->next
;
2292 DEBUG (g_print ("\tforced copy from %s to %s\n",
2293 mono_arch_regname (src
), mono_arch_regname (dest
)));
2297 /*========================= End of Function ========================*/
2299 /*------------------------------------------------------------------*/
2301 /* Name - create_spilled_store */
2303 /* Function - Spill register to storage. */
2305 /*------------------------------------------------------------------*/
2308 create_spilled_store (MonoCompile
*cfg
, int spill
, int reg
, int prev_reg
, MonoInst
*ins
)
2311 MONO_INST_NEW (cfg
, store
, OP_STORE_MEMBASE_REG
);
2313 store
->inst_destbasereg
= cfg
->frame_reg
;
2314 store
->inst_offset
= mono_spillvar_offset (cfg
, spill
);
2316 store
->next
= ins
->next
;
2319 DEBUG (g_print ("SPILLED STORE (%d at 0x%08x(%%sp)) R%d (from %s)\n",
2320 spill
, store
->inst_offset
, prev_reg
, mono_arch_regname (reg
)));
2324 /*========================= End of Function ========================*/
2326 /*------------------------------------------------------------------*/
2328 /* Name - create_spilled_store_float */
2330 /* Function - Spill floating point register to storage. */
2332 /*------------------------------------------------------------------*/
2335 create_spilled_store_float (MonoCompile
*cfg
, int spill
, int reg
, int prev_reg
, MonoInst
*ins
)
2338 MONO_INST_NEW (cfg
, store
, OP_STORER8_MEMBASE_REG
);
2340 store
->inst_destbasereg
= cfg
->frame_reg
;
2341 store
->inst_offset
= mono_spillvar_offset_float (cfg
, spill
);
2343 store
->next
= ins
->next
;
2346 DEBUG (g_print ("SPILLED STORE (%d at 0x%08x(%%sp)) R%d (from %s)\n",
2347 spill
, store
->inst_offset
, prev_reg
, mono_arch_regname (reg
)));
2351 /*========================= End of Function ========================*/
2353 /*------------------------------------------------------------------*/
2355 /* Name - insert_before_ins */
2357 /* Function - Insert an instruction before another. */
2359 /*------------------------------------------------------------------*/
2362 insert_before_ins (MonoInst
*ins
, InstList
*item
, MonoInst
* to_insert
)
2365 g_assert (item
->next
);
2366 prev
= item
->next
->data
;
2368 while (prev
->next
!= ins
)
2370 to_insert
->next
= ins
;
2371 prev
->next
= to_insert
;
2373 * needed otherwise in the next instruction we can add an ins to the
2374 * end and that would get past this instruction.
2376 item
->data
= to_insert
;
2379 /*========================= End of Function ========================*/
2381 /*------------------------------------------------------------------*/
2383 /* Name - alloc_int_reg */
2385 /* Function - Allocate a general register. */
2387 /*------------------------------------------------------------------*/
2390 alloc_int_reg (MonoCompile
*cfg
, InstList
*curinst
, MonoInst
*ins
, int sym_reg
, guint32 allow_mask
)
2392 int val
= cfg
->rs
->iassign
[sym_reg
];
2396 /* the register gets spilled after this inst */
2399 val
= mono_regstate_alloc_int (cfg
->rs
, allow_mask
);
2401 val
= get_register_spilling (cfg
, curinst
, ins
, allow_mask
, sym_reg
);
2402 cfg
->rs
->iassign
[sym_reg
] = val
;
2403 /* add option to store before the instruction for src registers */
2405 create_spilled_store (cfg
, spill
, val
, sym_reg
, ins
);
2407 cfg
->rs
->isymbolic
[val
] = sym_reg
;
2411 /*========================= End of Function ========================*/
2413 /*------------------------------------------------------------------*/
2415 /* Name - mono_arch_local_regalloc. */
2417 /* Function - We first scan the list of instructions and we */
2418 /* save the liveness information of each register */
2419 /* (when the register is first used, when its value */
2420 /* is set etc.). We also reverse the list of instr- */
2421 /* uctions (in the InstList list) because assigning */
2422 /* registers backwards allows for more tricks to be */
2425 /*------------------------------------------------------------------*/
2428 mono_arch_local_regalloc (MonoCompile
*cfg
, MonoBasicBlock
*bb
)
2431 MonoRegState
*rs
= cfg
->rs
;
2433 RegTrack
*reginfo
, *reginfof
;
2434 RegTrack
*reginfo1
, *reginfo2
, *reginfod
;
2435 InstList
*tmp
, *reversed
= NULL
;
2437 guint32 src1_mask
, src2_mask
, dest_mask
;
2438 guint32 cur_iregs
, cur_fregs
;
2442 rs
->next_vireg
= bb
->max_ireg
;
2443 rs
->next_vfreg
= bb
->max_freg
;
2444 mono_regstate_assign (rs
);
2445 reginfo
= mono_mempool_alloc0 (cfg
->mempool
, sizeof (RegTrack
) * rs
->next_vireg
);
2446 reginfof
= mono_mempool_alloc0 (cfg
->mempool
, sizeof (RegTrack
) * rs
->next_vfreg
);
2447 rs
->ifree_mask
= S390_CALLER_REGS
;
2448 rs
->ffree_mask
= S390_CALLER_FREGS
;
2452 DEBUG (g_print ("LOCAL regalloc: basic block: %d\n", bb
->block_num
));
2453 /* forward pass on the instructions to collect register liveness info */
2455 spec
= ins_spec
[ins
->opcode
];
2456 DEBUG (print_ins (i
, ins
));
2457 if (spec
[MONO_INST_CLOB
] == 'c') {
2458 MonoCallInst
* call
= (MonoCallInst
*)ins
;
2461 if (spec
[MONO_INST_SRC1
]) {
2462 if (spec
[MONO_INST_SRC1
] == 'f')
2463 reginfo1
= reginfof
;
2466 reginfo1
[ins
->sreg1
].prev_use
= reginfo1
[ins
->sreg1
].last_use
;
2467 reginfo1
[ins
->sreg1
].last_use
= i
;
2471 if (spec
[MONO_INST_SRC2
]) {
2472 if (spec
[MONO_INST_SRC2
] == 'f')
2473 reginfo2
= reginfof
;
2476 reginfo2
[ins
->sreg2
].prev_use
= reginfo2
[ins
->sreg2
].last_use
;
2477 reginfo2
[ins
->sreg2
].last_use
= i
;
2481 if (spec
[MONO_INST_DEST
]) {
2482 if (spec
[MONO_INST_DEST
] == 'f')
2483 reginfod
= reginfof
;
2486 if (spec
[MONO_INST_DEST
] != 'b') /* it's not just a base register */
2487 reginfod
[ins
->dreg
].killed_in
= i
;
2488 reginfod
[ins
->dreg
].prev_use
= reginfod
[ins
->dreg
].last_use
;
2489 reginfod
[ins
->dreg
].last_use
= i
;
2490 if (reginfod
[ins
->dreg
].born_in
== 0 || reginfod
[ins
->dreg
].born_in
> i
)
2491 reginfod
[ins
->dreg
].born_in
= i
;
2492 if (spec
[MONO_INST_DEST
] == 'l') {
2493 /* result in eax:edx, the virtual register is allocated sequentially */
2494 reginfod
[ins
->dreg
+ 1].prev_use
= reginfod
[ins
->dreg
+ 1].last_use
;
2495 reginfod
[ins
->dreg
+ 1].last_use
= i
;
2496 if (reginfod
[ins
->dreg
+ 1].born_in
== 0 || reginfod
[ins
->dreg
+ 1].born_in
> i
)
2497 reginfod
[ins
->dreg
+ 1].born_in
= i
;
2502 reversed
= inst_list_prepend (cfg
->mempool
, reversed
, ins
);
2507 cur_iregs
= S390_CALLER_REGS
;
2508 cur_fregs
= S390_CALLER_FREGS
;
2510 DEBUG (print_regtrack (reginfo
, rs
->next_vireg
));
2511 DEBUG (print_regtrack (reginfof
, rs
->next_vfreg
));
2514 int prev_dreg
, prev_sreg1
, prev_sreg2
;
2517 spec
= ins_spec
[ins
->opcode
];
2518 DEBUG (g_print ("processing:"));
2519 DEBUG (print_ins (i
, ins
));
2520 /* make the register available for allocation: FIXME add fp reg */
2521 if (ins
->opcode
== OP_SETREG
|| ins
->opcode
== OP_SETREGIMM
) {
2522 cur_iregs
|= 1 << ins
->dreg
;
2523 DEBUG (g_print ("adding %d to cur_iregs\n", ins
->dreg
));
2524 } else if (ins
->opcode
== OP_SETFREG
) {
2525 cur_fregs
|= 1 << ins
->dreg
;
2526 DEBUG (g_print ("adding %d to cur_fregs\n", ins
->dreg
));
2527 } else if (spec
[MONO_INST_CLOB
] == 'c') {
2528 MonoCallInst
*cinst
= (MonoCallInst
*)ins
;
2529 DEBUG (g_print ("excluding regs 0x%x from cur_iregs (0x%x)\n", cinst
->used_iregs
, cur_iregs
));
2530 DEBUG (g_print ("excluding fpregs 0x%x from cur_fregs (0x%x)\n", cinst
->used_fregs
, cur_fregs
));
2531 cur_iregs
&= ~cinst
->used_iregs
;
2532 cur_fregs
&= ~cinst
->used_fregs
;
2533 DEBUG (g_print ("available cur_iregs: 0x%x\n", cur_iregs
));
2534 DEBUG (g_print ("available cur_fregs: 0x%x\n", cur_fregs
));
2535 /* registers used by the calling convention are excluded from
2536 * allocation: they will be selectively enabled when they are
2537 * assigned by the special SETREG opcodes.
2540 dest_mask
= src1_mask
= src2_mask
= cur_iregs
;
2541 /* update for use with FP regs... */
2542 if (spec
[MONO_INST_DEST
] == 'f') {
2543 dest_mask
= cur_fregs
;
2544 if (ins
->dreg
>= MONO_MAX_FREGS
) {
2545 val
= rs
->fassign
[ins
->dreg
];
2546 prev_dreg
= ins
->dreg
;
2550 /* the register gets spilled after this inst */
2553 val
= mono_regstate_alloc_float (rs
, dest_mask
);
2555 val
= get_float_register_spilling (cfg
, tmp
, ins
, dest_mask
, ins
->dreg
);
2556 rs
->fassign
[ins
->dreg
] = val
;
2558 create_spilled_store_float (cfg
, spill
, val
, prev_dreg
, ins
);
2560 DEBUG (g_print ("\tassigned dreg %s to dest R%d\n", mono_arch_regname (val
), ins
->dreg
));
2561 rs
->fsymbolic
[val
] = prev_dreg
;
2563 if (spec
[MONO_INST_CLOB
] == 'c' && ins
->dreg
!= s390_f0
) {
2564 /* this instruction only outputs to s390_f0, need to copy */
2565 create_copy_ins_float (cfg
, ins
->dreg
, s390_f0
, ins
);
2570 if (freg_is_freeable (ins
->dreg
) && prev_dreg
>= 0 && (reginfo
[prev_dreg
].born_in
>= i
|| !(cur_fregs
& (1 << ins
->dreg
)))) {
2571 DEBUG (g_print ("\tfreeable %s (R%d) (born in %d)\n", mono_arch_regname (ins
->dreg
), prev_dreg
, reginfo
[prev_dreg
].born_in
));
2572 mono_regstate_free_float (rs
, ins
->dreg
);
2574 } else if (ins
->dreg
>= MONO_MAX_IREGS
) {
2575 val
= rs
->iassign
[ins
->dreg
];
2576 prev_dreg
= ins
->dreg
;
2580 /* the register gets spilled after this inst */
2583 val
= mono_regstate_alloc_int (rs
, dest_mask
);
2585 val
= get_register_spilling (cfg
, tmp
, ins
, dest_mask
, ins
->dreg
);
2586 rs
->iassign
[ins
->dreg
] = val
;
2588 create_spilled_store (cfg
, spill
, val
, prev_dreg
, ins
);
2590 DEBUG (g_print ("\tassigned dreg %s to dest R%d\n", mono_arch_regname (val
), ins
->dreg
));
2591 rs
->isymbolic
[val
] = prev_dreg
;
2593 if (spec
[MONO_INST_DEST
] == 'l') {
2594 int hreg
= prev_dreg
+ 1;
2595 val
= rs
->iassign
[hreg
];
2599 /* the register gets spilled after this inst */
2602 val
= mono_regstate_alloc_int (rs
, dest_mask
);
2604 val
= get_register_spilling (cfg
, tmp
, ins
, dest_mask
, hreg
);
2605 rs
->iassign
[hreg
] = val
;
2607 create_spilled_store (cfg
, spill
, val
, hreg
, ins
);
2609 DEBUG (g_print ("\tassigned hreg %s to dest R%d\n", mono_arch_regname (val
), hreg
));
2610 rs
->isymbolic
[val
] = hreg
;
2611 /* FIXME:? ins->dreg = val; */
2612 if (ins
->dreg
== s390_r3
) {
2614 create_copy_ins (cfg
, val
, s390_r2
, ins
);
2615 } else if (ins
->dreg
== s390_r2
) {
2616 if (val
== s390_r3
) {
2618 create_copy_ins (cfg
, s390_r3
, s390_r0
, ins
);
2619 create_copy_ins (cfg
, s390_r2
, s390_r3
, ins
);
2620 create_copy_ins (cfg
, s390_r0
, s390_r2
, ins
);
2622 /* two forced copies */
2623 create_copy_ins (cfg
, ins
->dreg
, s390_r3
, ins
);
2624 create_copy_ins (cfg
, val
, s390_r2
, ins
);
2627 if (val
== s390_r2
) {
2628 create_copy_ins (cfg
, ins
->dreg
, s390_r2
, ins
);
2630 /* two forced copies */
2631 create_copy_ins (cfg
, val
, s390_r2
, ins
);
2632 create_copy_ins (cfg
, ins
->dreg
, s390_r3
, ins
);
2635 if (reg_is_freeable (val
) && hreg
>= 0 && (reginfo
[hreg
].born_in
>= i
&& !(cur_iregs
& (1 << val
)))) {
2636 DEBUG (g_print ("\tfreeable %s (R%d)\n", mono_arch_regname (val
), hreg
));
2637 mono_regstate_free_int (rs
, val
);
2639 } else if (spec
[MONO_INST_DEST
] == 'a' && ins
->dreg
!= s390_r2
&& spec
[MONO_INST_CLOB
] != 'd') {
2640 /* this instruction only outputs to s390_r2, need to copy */
2641 create_copy_ins (cfg
, ins
->dreg
, s390_r2
, ins
);
2646 if (spec
[MONO_INST_DEST
] == 'f' &&
2647 freg_is_freeable (ins
->dreg
) &&
2648 prev_dreg
>= 0 && (reginfof
[prev_dreg
].born_in
>= i
)) {
2649 DEBUG (g_print ("\tfreeable %s (R%d) (born in %d)\n", mono_arch_regname (ins
->dreg
), prev_dreg
, reginfo
[prev_dreg
].born_in
));
2650 mono_regstate_free_float (rs
, ins
->dreg
);
2651 } else if (spec
[MONO_INST_DEST
] != 'f' &&
2652 reg_is_freeable (ins
->dreg
) &&
2653 prev_dreg
>= 0 && (reginfo
[prev_dreg
].born_in
>= i
)) {
2654 DEBUG (g_print ("\tfreeable %s (R%d) (born in %d)\n", mono_arch_regname (ins
->dreg
), prev_dreg
, reginfo
[prev_dreg
].born_in
));
2655 mono_regstate_free_int (rs
, ins
->dreg
);
2657 if (spec
[MONO_INST_SRC1
] == 'f') {
2658 src1_mask
= cur_fregs
;
2659 if (ins
->sreg1
>= MONO_MAX_FREGS
) {
2660 val
= rs
->fassign
[ins
->sreg1
];
2661 prev_sreg1
= ins
->sreg1
;
2665 /* the register gets spilled after this inst */
2668 //g_assert (val == -1); /* source cannot be spilled */
2669 val
= mono_regstate_alloc_float (rs
, src1_mask
);
2671 val
= get_float_register_spilling (cfg
, tmp
, ins
, src1_mask
, ins
->sreg1
);
2672 rs
->fassign
[ins
->sreg1
] = val
;
2673 DEBUG (g_print ("\tassigned sreg1 %s to R%d\n", mono_arch_regname (val
), ins
->sreg1
));
2675 MonoInst
*store
= create_spilled_store_float (cfg
, spill
, val
, prev_sreg1
, NULL
);
2676 insert_before_ins (ins
, tmp
, store
);
2679 rs
->fsymbolic
[val
] = prev_sreg1
;
2684 } else if (ins
->sreg1
>= MONO_MAX_IREGS
) {
2685 val
= rs
->iassign
[ins
->sreg1
];
2686 prev_sreg1
= ins
->sreg1
;
2690 /* the register gets spilled after this inst */
2692 printf("val: %d spill: %d ins->sreg1: %d\n",val
,spill
,ins
->sreg1
);
2694 val
= mono_regstate_alloc_int (rs
, src1_mask
);
2696 val
= get_register_spilling (cfg
, tmp
, ins
, src1_mask
, ins
->sreg1
);
2697 rs
->iassign
[ins
->sreg1
] = val
;
2698 DEBUG (g_print ("\tassigned sreg1 %s to R%d\n", mono_arch_regname (val
), ins
->sreg1
));
2700 MonoInst
*store
= create_spilled_store (cfg
, spill
, val
, prev_sreg1
, NULL
);
2701 insert_before_ins (ins
, tmp
, store
);
2704 rs
->isymbolic
[val
] = prev_sreg1
;
2709 /*----------------------------------------------*/
2710 /* handle clobbering of sreg1 */
2711 /*----------------------------------------------*/
2712 if ((spec
[MONO_INST_CLOB
] == '1' ||
2713 spec
[MONO_INST_CLOB
] == 's') &&
2714 ins
->dreg
!= ins
->sreg1
) {
2715 MonoInst
*copy
= create_copy_ins (cfg
, ins
->dreg
, ins
->sreg1
, NULL
);
2716 DEBUG (g_print ("\tneed to copy sreg1 %s to dreg %s\n",
2717 mono_arch_regname (ins
->sreg1
),
2718 mono_arch_regname (ins
->dreg
)));
2719 if (ins
->sreg2
== -1 || spec
[MONO_INST_CLOB
] == 's') {
2720 /* note: the copy is inserted before the current instruction! */
2721 insert_before_ins (ins
, tmp
, copy
);
2722 /* we set sreg1 to dest as well */
2723 prev_sreg1
= ins
->sreg1
= ins
->dreg
;
2725 /* inserted after the operation */
2726 copy
->next
= ins
->next
;
2731 if (spec
[MONO_INST_SRC2
] == 'f') {
2732 src2_mask
= cur_fregs
;
2733 if (ins
->sreg2
>= MONO_MAX_FREGS
) {
2734 val
= rs
->fassign
[ins
->sreg2
];
2735 prev_sreg2
= ins
->sreg2
;
2739 /* the register gets spilled after this inst */
2742 val
= mono_regstate_alloc_float (rs
, src2_mask
);
2744 val
= get_float_register_spilling (cfg
, tmp
, ins
, src2_mask
, ins
->sreg2
);
2745 rs
->fassign
[ins
->sreg2
] = val
;
2746 DEBUG (g_print ("\tassigned sreg2 %s to R%d\n", mono_arch_regname (val
), ins
->sreg2
));
2748 create_spilled_store_float (cfg
, spill
, val
, prev_sreg2
, ins
);
2750 rs
->fsymbolic
[val
] = prev_sreg2
;
2755 } else if (ins
->sreg2
>= MONO_MAX_IREGS
) {
2756 val
= rs
->iassign
[ins
->sreg2
];
2757 prev_sreg2
= ins
->sreg2
;
2761 /* the register gets spilled after this inst */
2764 val
= mono_regstate_alloc_int (rs
, src2_mask
);
2766 val
= get_register_spilling (cfg
, tmp
, ins
, src2_mask
, ins
->sreg2
);
2767 rs
->iassign
[ins
->sreg2
] = val
;
2768 DEBUG (g_print ("\tassigned sreg2 %s to R%d\n", mono_arch_regname (val
), ins
->sreg2
));
2770 create_spilled_store (cfg
, spill
, val
, prev_sreg2
, ins
);
2772 rs
->isymbolic
[val
] = prev_sreg2
;
2778 if (spec
[MONO_INST_CLOB
] == 'c') {
2780 guint32 clob_mask
= S390_CALLER_REGS
;
2781 for (j
= 0; j
< MONO_MAX_IREGS
; ++j
) {
2783 if ((clob_mask
& s
) && !(rs
->ifree_mask
& s
) && j
!= ins
->sreg1
) {
2784 //g_warning ("register %s busy at call site\n", mono_arch_regname (j));
2788 /*if (reg_is_freeable (ins->sreg1) && prev_sreg1 >= 0 && reginfo [prev_sreg1].born_in >= i) {
2789 DEBUG (g_print ("freeable %s\n", mono_arch_regname (ins->sreg1)));
2790 mono_regstate_free_int (rs, ins->sreg1);
2792 if (reg_is_freeable (ins->sreg2) && prev_sreg2 >= 0 && reginfo [prev_sreg2].born_in >= i) {
2793 DEBUG (g_print ("freeable %s\n", mono_arch_regname (ins->sreg2)));
2794 mono_regstate_free_int (rs, ins->sreg2);
2797 //DEBUG (print_ins (i, ins));
2802 /*========================= End of Function ========================*/
2804 /*------------------------------------------------------------------*/
2806 /* Name - emit_float_to_int */
2808 /* Function - Create instructions which will convert a floating */
2809 /* point value to integer. */
2811 /*------------------------------------------------------------------*/
2814 emit_float_to_int (MonoCompile
*cfg
, guchar
*code
, int dreg
, int sreg
, int size
, gboolean is_signed
)
2816 /* sreg is a float, dreg is an integer reg. */
2818 s390_cfdbr (code
, dreg
, 5, sreg
);
2820 s390_basr (code
, s390_r13
, 0);
2822 s390_double (code
, 0x41e0000000000000);
2823 s390_double (code
, 0x41f0000000000000);
2824 s390_ldr (code
, s390_f0
, sreg
);
2825 s390_cdb (code
, s390_f0
, 0, s390_r13
, 0);
2827 s390_sdb (code
, s390_f0
, 0, s390_r13
, 8);
2828 s390_cfdbr (code
, dreg
, 7, s390_f0
);
2830 s390_cfdbr (code
, dreg
, 5, sreg
);
2835 /*========================= End of Function ========================*/
2837 /*------------------------------------------------------------------*/
2839 /* Name - mono_emit_stack_alloc */
2843 /*------------------------------------------------------------------*/
2845 static unsigned char*
2846 mono_emit_stack_alloc (guchar
*code
, MonoInst
* tree
)
2851 /*========================= End of Function ========================*/
2853 /*------------------------------------------------------------------*/
2855 /* Name - mono_arch_output_basic_block */
2857 /* Function - Perform the "real" work of emitting instructions */
2858 /* that will do the work of in the basic block. */
2860 /*------------------------------------------------------------------*/
2863 mono_arch_output_basic_block (MonoCompile
*cfg
, MonoBasicBlock
*bb
)
2868 guint8
*code
= cfg
->native_code
+ cfg
->code_len
;
2869 MonoInst
*last_ins
= NULL
;
2870 guint last_offset
= 0;
2873 if (cfg
->opt
& MONO_OPT_PEEPHOLE
)
2874 peephole_pass (cfg
, bb
);
2876 /* we don't align basic blocks of loops on s390 */
2878 if (cfg
->verbose_level
> 2)
2879 g_print ("Basic block %d starting at offset 0x%x\n", bb
->block_num
, bb
->native_offset
);
2881 cpos
= bb
->max_offset
;
2883 if (cfg
->prof_options
& MONO_PROFILE_COVERAGE
) {
2884 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
2885 //g_assert (!mono_compile_aot);
2888 // cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
2889 /* this is not thread save, but good enough */
2890 /* fixme: howto handle overflows? */
2891 //x86_inc_mem (code, &cov->data [bb->dfn].count);
2896 offset
= code
- cfg
->native_code
;
2898 max_len
= ((guint8
*)ins_spec
[ins
->opcode
])[MONO_INST_LEN
];
2900 if (offset
> (cfg
->code_size
- max_len
- 16)) {
2901 cfg
->code_size
*= 2;
2902 cfg
->native_code
= g_realloc (cfg
->native_code
, cfg
->code_size
);
2903 code
= cfg
->native_code
+ offset
;
2906 switch (ins
->opcode
) {
2907 case OP_STOREI1_MEMBASE_IMM
:
2908 s390_lhi (code
, s390_r14
, ins
->inst_imm
);
2909 if (s390_is_uimm12(ins
->inst_offset
))
2910 s390_stc (code
, s390_r14
, 0, ins
->inst_destbasereg
, ins
->inst_offset
);
2912 s390_basr (code
, s390_r13
, 0);
2914 s390_word (code
, ins
->inst_offset
);
2915 s390_l (code
, s390_r13
, 0, s390_r13
, 4);
2916 s390_stc (code
, s390_r14
, s390_r13
, ins
->inst_destbasereg
, 0);
2919 case OP_STOREI2_MEMBASE_IMM
:
2920 s390_lhi (code
, s390_r14
, ins
->inst_imm
);
2921 if (s390_is_uimm12(ins
->inst_offset
)) {
2922 s390_sth (code
, s390_r14
, 0, ins
->inst_destbasereg
, ins
->inst_offset
);
2924 s390_basr (code
, s390_r14
, 0);
2926 s390_word (code
, ins
->inst_offset
);
2927 s390_l (code
, s390_r13
, 0, s390_r13
, 4);
2928 s390_sth (code
, s390_r14
, s390_r13
, ins
->inst_destbasereg
, 0);
2931 case OP_STORE_MEMBASE_IMM
:
2932 case OP_STOREI4_MEMBASE_IMM
:
2933 if (s390_is_imm16(ins
->inst_imm
)) {
2934 s390_lhi (code
, s390_r14
, ins
->inst_imm
);
2936 s390_basr (code
, s390_r13
, 0);
2938 s390_word (code
, ins
->inst_imm
);
2939 s390_l (code
, s390_r14
, 0, s390_r13
, 4);
2941 if (s390_is_uimm12(ins
->inst_offset
)) {
2942 s390_st (code
, s390_r14
, 0, ins
->inst_destbasereg
, ins
->inst_offset
);
2944 s390_basr (code
, s390_r13
, 0);
2946 s390_word (code
, ins
->inst_offset
);
2947 s390_l (code
, s390_r13
, 0, s390_r13
, 4);
2948 s390_st (code
, s390_r14
, s390_r13
, ins
->inst_destbasereg
, 0);
2951 case OP_STOREI1_MEMBASE_REG
:
2952 if (s390_is_uimm12(ins
->inst_offset
)) {
2953 s390_stc (code
, ins
->sreg1
, 0, ins
->inst_destbasereg
, ins
->inst_offset
);
2955 s390_basr (code
, s390_r13
, 0);
2957 s390_word (code
, ins
->inst_offset
);
2958 s390_l (code
, s390_r13
, 0, s390_r13
, 4);
2959 s390_stc (code
, ins
->sreg1
, s390_r13
, ins
->inst_destbasereg
, 0);
2962 case OP_STOREI2_MEMBASE_REG
:
2963 if (s390_is_uimm12(ins
->inst_offset
)) {
2964 s390_sth (code
, ins
->sreg1
, 0, ins
->inst_destbasereg
, ins
->inst_offset
);
2966 s390_basr (code
, s390_r13
, 0);
2968 s390_word (code
, ins
->inst_offset
);
2969 s390_l (code
, s390_r13
, 0, s390_r13
, 4);
2970 s390_sth (code
, ins
->sreg1
, s390_r13
, ins
->inst_destbasereg
, 0);
2973 case OP_STORE_MEMBASE_REG
:
2974 case OP_STOREI4_MEMBASE_REG
:
2975 if (s390_is_uimm12(ins
->inst_offset
)) {
2976 s390_st (code
, ins
->sreg1
, 0, ins
->inst_destbasereg
, ins
->inst_offset
);
2978 s390_basr (code
, s390_r13
, 0);
2980 s390_word (code
, ins
->inst_offset
);
2981 s390_l (code
, s390_r13
, 0, s390_r13
, 4);
2982 s390_st (code
, ins
->sreg1
, s390_r13
, ins
->inst_destbasereg
, 0);
2988 s390_basr (code
, s390_r13
, 0);
2990 s390_word (code
, ins
->inst_p0
);
2991 s390_l (code
, s390_r13
, 0, s390_r13
, 4);
2992 s390_l (code
, ins
->dreg
, 0, s390_r13
, 0);
2995 g_assert_not_reached ();
2997 case OP_LOAD_MEMBASE
:
2998 case OP_LOADI4_MEMBASE
:
2999 case OP_LOADU4_MEMBASE
:
3000 if (s390_is_uimm12(ins
->inst_offset
))
3001 s390_l (code
, ins
->dreg
, 0, ins
->inst_basereg
, ins
->inst_offset
);
3003 if (s390_is_imm16(ins
->inst_offset
)) {
3004 s390_lhi (code
, s390_r13
, ins
->inst_offset
);
3005 s390_l (code
, ins
->dreg
, s390_r13
, ins
->inst_basereg
, 0);
3007 s390_basr (code
, s390_r13
, 0);
3009 s390_word (code
, ins
->inst_offset
);
3010 s390_l (code
, s390_r13
, 0, s390_r13
, 4);
3011 s390_l (code
, ins
->dreg
, s390_r13
, ins
->inst_basereg
, 0);
3015 case OP_LOADU1_MEMBASE
:
3016 s390_lhi (code
, s390_r0
, 0);
3017 if (s390_is_uimm12(ins
->inst_offset
))
3018 s390_ic (code
, s390_r0
, 0, ins
->inst_basereg
, ins
->inst_offset
);
3020 s390_basr (code
, s390_r13
, 0);
3022 s390_word (code
, ins
->inst_offset
);
3023 s390_l (code
, s390_r13
, 0, s390_r13
, 4);
3024 s390_ic (code
, s390_r0
, s390_r13
, ins
->inst_basereg
, 0);
3026 s390_lr (code
, ins
->dreg
, s390_r0
);
3028 case OP_LOADI1_MEMBASE
:
3029 s390_lhi (code
, s390_r0
, 0);
3030 if (s390_is_uimm12(ins
->inst_offset
))
3031 s390_ic (code
, s390_r0
, 0, ins
->inst_basereg
, ins
->inst_offset
);
3033 s390_basr (code
, s390_r13
, 0);
3035 s390_word (code
, ins
->inst_offset
);
3036 s390_l (code
, s390_r13
, 0, s390_r13
, 4);
3037 s390_ic (code
, s390_r0
, s390_r13
, ins
->inst_basereg
, 0);
3039 s390_lhi (code
, s390_r13
, 0x80);
3040 s390_nr (code
, s390_r13
, s390_r0
);
3042 s390_lhi (code
, s390_r13
, 0xff00);
3043 s390_or (code
, s390_r0
, s390_r13
);
3044 s390_lr (code
, ins
->dreg
, s390_r0
);
3046 case OP_LOADU2_MEMBASE
:
3047 s390_lhi (code
, s390_r0
, 0);
3048 if (s390_is_uimm12(ins
->inst_offset
))
3049 s390_icm (code
, s390_r0
, 3, ins
->inst_basereg
, ins
->inst_offset
);
3051 s390_basr (code
, s390_r13
, 0);
3053 s390_word (code
, ins
->inst_offset
);
3054 s390_l (code
, s390_r13
, 0, s390_r13
, 4);
3055 s390_ar (code
, s390_r13
, ins
->inst_basereg
);
3056 s390_icm (code
, s390_r0
, 3, s390_r13
, 0);
3058 s390_lr (code
, ins
->dreg
, s390_r0
);
3060 case OP_LOADI2_MEMBASE
:
3061 s390_lhi (code
, s390_r0
, 0);
3062 if (s390_is_uimm12(ins
->inst_offset
))
3063 s390_lh (code
, s390_r0
, 0, ins
->inst_basereg
, ins
->inst_offset
);
3065 s390_basr (code
, s390_r13
, 0);
3067 s390_word (code
, ins
->inst_offset
);
3068 s390_l (code
, s390_r13
, 0, s390_r13
, 4);
3069 s390_lh (code
, s390_r0
, s390_r13
, ins
->inst_basereg
, 0);
3071 s390_lr (code
, ins
->dreg
, s390_r0
);
3074 s390_lhi (code
, s390_r0
, 0x80);
3075 if (ins
->dreg
!= ins
->sreg1
) {
3076 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3078 s390_nr (code
, s390_r0
, ins
->sreg1
);
3080 s390_lhi (code
, s390_r13
, -1);
3081 s390_sll (code
, s390_r13
, 0, 8);
3082 s390_or (code
, ins
->dreg
, s390_r13
);
3085 s390_lhi (code
, s390_r0
, 0x80);
3086 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3087 s390_nr (code
, s390_r0
, ins
->sreg1
);
3089 s390_lhi (code
, s390_r13
, -1);
3090 s390_sll (code
, s390_r13
, 0, 16);
3091 s390_or (code
, ins
->dreg
, s390_r13
);
3094 s390_lhi (code
, s390_r0
, 0xff);
3095 if (ins
->dreg
!= ins
->sreg1
) {
3096 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3098 s390_nr (code
, ins
->dreg
, s390_r0
);
3101 s390_lhi (code
, s390_r0
, -1);
3102 s390_sll (code
, s390_r0
, 0, 16);
3103 s390_srl (code
, s390_r0
, 0, 16);
3104 if (ins
->dreg
!= ins
->sreg1
) {
3105 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3107 s390_nr (code
, ins
->dreg
, s390_r0
);
3111 ((ins
->next
->opcode
>= CEE_BNE_UN
) &&
3112 (ins
->next
->opcode
<= CEE_BLT_UN
)))
3113 s390_clr (code
, ins
->sreg1
, ins
->sreg2
);
3115 s390_cr (code
, ins
->sreg1
, ins
->sreg2
);
3117 case OP_COMPARE_IMM
:
3118 if (s390_is_imm16 (ins
->inst_imm
)) {
3119 s390_lhi (code
, s390_r0
, ins
->inst_imm
);
3121 ((ins
->next
->opcode
>= CEE_BNE_UN
) &&
3122 (ins
->next
->opcode
<= CEE_BLT_UN
)))
3123 s390_clr (code
, ins
->sreg1
, s390_r0
);
3125 s390_cr (code
, ins
->sreg1
, s390_r0
);
3128 s390_basr (code
, s390_r13
, 0);
3130 s390_word (code
, ins
->inst_imm
);
3132 ((ins
->next
->opcode
>= CEE_BNE_UN
) &&
3133 (ins
->next
->opcode
<= CEE_BLT_UN
)))
3134 s390_cl (code
, ins
->sreg1
, 0, s390_r13
, 4);
3136 s390_c (code
, ins
->sreg1
, 0, s390_r13
, 4);
3139 case OP_X86_TEST_NULL
:
3140 s390_ltr (code
, ins
->sreg1
, ins
->sreg1
);
3146 if (ins
->dreg
!= ins
->sreg1
) {
3147 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3149 s390_alr (code
, ins
->dreg
, ins
->sreg2
);
3152 if (ins
->dreg
!= ins
->sreg1
) {
3153 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3155 s390_ar (code
, ins
->dreg
, ins
->sreg2
);
3158 if (ins
->dreg
!= ins
->sreg1
) {
3159 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3161 s390_alcr (code
, ins
->dreg
, ins
->sreg2
);
3165 (ins
->next
->opcode
== OP_ADC_IMM
)) {
3166 s390_basr (code
, s390_r13
, 0);
3168 s390_word (code
, ins
->inst_imm
);
3169 if (ins
->dreg
!= ins
->sreg1
) {
3170 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3172 s390_al (code
, ins
->dreg
, 0, s390_r13
, 4);
3174 if (s390_is_imm16 (ins
->inst_imm
)) {
3175 if (ins
->dreg
!= ins
->sreg1
) {
3176 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3178 s390_ahi (code
, ins
->dreg
, ins
->inst_imm
);
3180 s390_basr (code
, s390_r13
, 0);
3182 s390_word (code
, ins
->inst_imm
);
3183 if (ins
->dreg
!= ins
->sreg1
) {
3184 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3186 s390_a (code
, ins
->dreg
, 0, s390_r13
, 4);
3191 if (s390_is_imm16 (ins
->inst_imm
)) {
3192 if (ins
->dreg
!= ins
->sreg1
) {
3193 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3195 s390_lhi (code
, s390_r0
, ins
->inst_imm
);
3196 s390_alcr (code
, ins
->dreg
, s390_r0
);
3198 s390_basr (code
, s390_r13
, 0);
3200 s390_word (code
, ins
->inst_imm
);
3201 s390_l (code
, s390_r13
, 0, s390_r13
, 4);
3202 s390_alcr (code
, ins
->dreg
, s390_r13
);
3206 if (ins
->dreg
!= ins
->sreg1
) {
3207 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3209 s390_sr (code
, ins
->dreg
, ins
->sreg2
);
3212 if (ins
->dreg
!= ins
->sreg1
) {
3213 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3215 s390_sr (code
, ins
->dreg
, ins
->sreg2
);
3218 if (ins
->dreg
!= ins
->sreg1
) {
3219 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3221 s390_slbr (code
, ins
->dreg
, ins
->sreg2
);
3224 if (s390_is_imm16 (-ins
->inst_imm
)) {
3225 if (ins
->dreg
!= ins
->sreg1
) {
3226 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3228 s390_ahi (code
, ins
->dreg
, -ins
->inst_imm
);
3230 s390_basr (code
, s390_r13
, 0);
3232 s390_word (code
, ins
->inst_imm
);
3233 if (ins
->dreg
!= ins
->sreg1
) {
3234 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3236 s390_s (code
, ins
->dreg
, 0, s390_r13
, 4);
3240 s390_basr (code
, s390_r13
, 0);
3242 s390_word (code
, ins
->inst_imm
);
3243 s390_sl (code
, ins
->dreg
, 0, s390_r13
, 4);
3246 if (ins
->sreg1
== ins
->dreg
) {
3247 s390_nr (code
, ins
->dreg
, ins
->sreg2
);
3250 if (ins
->sreg2
== ins
->dreg
) {
3251 s390_nr (code
, ins
->dreg
, ins
->sreg1
);
3254 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3255 s390_nr (code
, ins
->dreg
, ins
->sreg2
);
3260 if (s390_is_imm16 (ins
->inst_imm
)) {
3261 s390_lhi (code
, s390_r0
, ins
->inst_imm
);
3262 if (ins
->dreg
!= ins
->sreg1
) {
3263 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3265 s390_nr (code
, ins
->dreg
, s390_r0
);
3267 s390_basr (code
, s390_r13
, 0);
3269 s390_word (code
, ins
->inst_imm
);
3270 if (ins
->dreg
!= ins
->sreg1
) {
3271 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3273 s390_n (code
, ins
->dreg
, 0, s390_r13
, 4);
3277 s390_lr (code
, s390_r0
, ins
->sreg1
);
3278 s390_srda (code
, s390_r0
, 0, 32);
3279 s390_dr (code
, s390_r0
, ins
->sreg2
);
3280 s390_lr (code
, ins
->dreg
, s390_r1
);
3283 s390_lr (code
, s390_r0
, ins
->sreg1
);
3284 s390_srdl (code
, s390_r0
, 0, 32);
3285 s390_dlr (code
, s390_r0
, ins
->sreg2
);
3286 s390_lr (code
, ins
->dreg
, s390_r1
);
3289 if (s390_is_imm16 (ins
->inst_imm
)) {
3290 s390_lhi (code
, s390_r13
, ins
->inst_imm
);
3291 s390_lr (code
, s390_r0
, ins
->sreg1
);
3293 s390_basr (code
, s390_r13
, 0);
3295 s390_word (code
, ins
->inst_imm
);
3296 s390_lr (code
, s390_r0
, ins
->sreg1
);
3297 s390_l (code
, s390_r13
, 0, s390_r13
, 4);
3299 s390_srda (code
, s390_r0
, 0, 32);
3300 s390_dr (code
, s390_r0
, ins
->sreg2
);
3301 s390_lr (code
, ins
->dreg
, s390_r1
);
3304 s390_lr (code
, s390_r0
, ins
->sreg1
);
3305 s390_srda (code
, s390_r0
, 0, 32);
3306 s390_dr (code
, s390_r0
, ins
->sreg2
);
3307 s390_lr (code
, ins
->dreg
, s390_r0
);
3310 s390_lr (code
, s390_r0
, ins
->sreg1
);
3311 s390_srdl (code
, s390_r0
, 0, 32);
3312 s390_dlr (code
, s390_r0
, ins
->sreg2
);
3313 s390_lr (code
, ins
->dreg
, s390_r0
);
3316 if (s390_is_imm16 (ins
->inst_imm
)) {
3317 s390_lhi (code
, s390_r13
, ins
->inst_imm
);
3318 s390_lr (code
, s390_r0
, ins
->sreg1
);
3320 s390_basr (code
, s390_r13
, 0);
3322 s390_word (code
, ins
->inst_imm
);
3323 s390_lr (code
, s390_r0
, ins
->sreg1
);
3324 s390_l (code
, s390_r13
, 0, s390_r13
, 4);
3326 s390_srda (code
, s390_r0
, 0, 32);
3327 s390_dr (code
, s390_r0
, ins
->sreg2
);
3328 s390_lr (code
, ins
->dreg
, s390_r0
);
3331 if (ins
->sreg1
== ins
->dreg
) {
3332 s390_or (code
, ins
->dreg
, ins
->sreg2
);
3335 if (ins
->sreg2
== ins
->dreg
) {
3336 s390_or (code
, ins
->dreg
, ins
->sreg1
);
3339 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3340 s390_or (code
, ins
->dreg
, ins
->sreg2
);
3345 if (s390_is_imm16 (ins
->inst_imm
)) {
3346 s390_lhi (code
, s390_r0
, ins
->inst_imm
);
3347 if (ins
->dreg
!= ins
->sreg1
) {
3348 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3350 s390_or (code
, ins
->dreg
, s390_r0
);
3352 s390_bras (code
, s390_r13
, 4);
3353 s390_word (code
, ins
->inst_imm
);
3354 if (ins
->dreg
!= ins
->sreg1
) {
3355 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3357 s390_o (code
, ins
->dreg
, 0, s390_r13
, 0);
3361 if (ins
->sreg1
== ins
->dreg
) {
3362 s390_xr (code
, ins
->dreg
, ins
->sreg2
);
3365 if (ins
->sreg2
== ins
->dreg
) {
3366 s390_xr (code
, ins
->dreg
, ins
->sreg1
);
3369 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3370 s390_xr (code
, ins
->dreg
, ins
->sreg2
);
3375 if (s390_is_imm16 (ins
->inst_imm
)) {
3376 s390_lhi (code
, s390_r0
, ins
->inst_imm
);
3377 if (ins
->dreg
!= ins
->sreg1
) {
3378 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3380 s390_xr (code
, ins
->dreg
, s390_r0
);
3382 s390_basr (code
, s390_r13
, 0);
3384 s390_word (code
, ins
->inst_imm
);
3385 if (ins
->dreg
!= ins
->sreg1
) {
3386 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3388 s390_x (code
, ins
->dreg
, 0, s390_r13
, 4);
3392 if (ins
->sreg1
!= ins
->dreg
) {
3393 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3395 s390_sll (code
, ins
->dreg
, ins
->sreg2
, 0);
3398 if (ins
->sreg1
!= ins
->dreg
) {
3399 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3401 s390_sll (code
, ins
->dreg
, 0, (ins
->inst_imm
& 0x1f));
3404 if (ins
->sreg1
!= ins
->dreg
) {
3405 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3407 s390_sra (code
, ins
->dreg
, ins
->sreg2
, 0);
3410 if (ins
->sreg1
!= ins
->dreg
) {
3411 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3413 s390_sra (code
, ins
->dreg
, 0, (ins
->inst_imm
& 0x1f));
3416 if (ins
->sreg1
!= ins
->dreg
) {
3417 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3419 s390_srl (code
, ins
->dreg
, 0, (ins
->inst_imm
& 0x1f));
3422 if (ins
->sreg1
!= ins
->dreg
) {
3423 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3425 s390_srl (code
, ins
->dreg
, ins
->sreg2
, 0);
3428 if (ins
->sreg1
!= ins
->dreg
) {
3429 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3431 s390_lhi (code
, s390_r0
, -1);
3432 s390_xr (code
, ins
->dreg
, s390_r0
);
3435 s390_lcr (code
, ins
->dreg
, ins
->sreg1
);
3438 if (ins
->sreg1
== ins
->dreg
) {
3439 s390_msr (code
, ins
->dreg
, ins
->sreg2
);
3442 if (ins
->sreg2
== ins
->dreg
) {
3443 s390_msr (code
, ins
->dreg
, ins
->sreg1
);
3446 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3447 s390_msr (code
, ins
->dreg
, ins
->sreg2
);
3452 if (s390_is_imm16 (ins
->inst_imm
)) {
3453 s390_lhi (code
, s390_r13
, ins
->inst_imm
);
3455 s390_basr (code
, s390_r13
, 0);
3457 s390_word (code
, ins
->inst_imm
);
3458 if (ins
->dreg
!= ins
->sreg1
) {
3459 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3461 s390_l (code
, s390_r13
, 0, s390_r13
, 4);
3463 s390_msr (code
, ins
->dreg
, s390_r13
);
3466 s390_lhi (code
, s390_r0
, 0);
3467 s390_lr (code
, s390_r1
, ins
->sreg1
);
3468 s390_mr (code
, s390_r0
, ins
->sreg2
);
3469 s390_ltr (code
, s390_r0
, s390_r0
);
3470 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_NZ
, "OverflowException");
3471 s390_lr (code
, ins
->dreg
, s390_r1
);
3473 case CEE_MUL_OVF_UN
:
3474 s390_lhi (code
, s390_r0
, 0);
3475 s390_lr (code
, s390_r1
, ins
->sreg1
);
3476 s390_mlr (code
, s390_r0
, ins
->sreg2
);
3477 s390_ltr (code
, s390_r0
, s390_r0
);
3478 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_NZ
, "OverflowException");
3479 s390_lr (code
, ins
->dreg
, s390_r1
);
3482 s390_l (code
, s390_r0
, 0, ins
->sreg1
, 4);
3483 s390_lr (code
, s390_r14
, s390_r0
);
3484 s390_srda (code
, s390_r0
, 0, 32);
3485 s390_m (code
, s390_r0
, 0, ins
->sreg2
, 4);
3486 s390_srl (code
, s390_r14
, 0, 31);
3487 s390_a (code
, s390_r14
, 0, ins
->sreg1
, 0);
3488 s390_l (code
, s390_r13
, 0, ins
->sreg2
, 0);
3489 s390_srl (code
, s390_r13
, 0, 31);
3490 s390_ms (code
, s390_r13
, 0, ins
->sreg1
, 4);
3491 s390_ar (code
, s390_r14
, s390_r13
);
3492 s390_st (code
, s390_r14
, 0, ins
->dreg
, 0);
3493 s390_st (code
, s390_r1
, 0, ins
->dreg
, 4);
3497 if (s390_is_imm16(ins
->inst_c0
)) {
3498 s390_lhi (code
, ins
->dreg
, ins
->inst_c0
);
3500 s390_basr (code
, s390_r13
, 0);
3502 s390_word (code
, ins
->inst_c0
);
3503 s390_l (code
, ins
->dreg
, 0, s390_r13
, 4);
3507 s390_basr (code
, s390_r13
, 0);
3509 mono_add_patch_info (cfg
, code
- cfg
->native_code
,
3510 (MonoJumpInfoType
)ins
->inst_i1
, ins
->inst_p0
);
3511 s390_word (code
, 0);
3512 s390_l (code
,ins
->dreg
, 0, s390_r13
, 4);
3518 if (ins
->dreg
!= ins
->sreg1
) {
3519 s390_lr (code
, ins
->dreg
, ins
->sreg1
);
3523 int saved
= ins
->sreg1
;
3524 if (ins
->sreg1
== s390_r2
) {
3525 s390_lr (code
, s390_r0
, ins
->sreg1
);
3528 if (ins
->sreg2
!= s390_r2
)
3529 s390_lr (code
, s390_r2
, ins
->sreg2
);
3530 if (saved
!= s390_r3
)
3531 s390_lr (code
, s390_r3
, saved
);
3536 if (ins
->dreg
!= ins
->sreg1
) {
3537 s390_ldr (code
, ins
->dreg
, ins
->sreg1
);
3540 case OP_FCONV_TO_R4
:
3541 s390_ledbr (code
, ins
->dreg
, ins
->sreg1
);
3544 g_assert_not_reached ();
3547 /* ensure ins->sreg1 is not NULL */
3548 s390_icm (code
, s390_r0
, 15, ins
->sreg1
, 0);
3555 call
= (MonoCallInst
*)ins
;
3556 if (ins
->flags
& MONO_INST_HAS_METHOD
)
3557 mono_add_patch_info (cfg
, offset
, MONO_PATCH_INFO_METHOD
, call
->method
);
3559 mono_add_patch_info (cfg
, offset
, MONO_PATCH_INFO_ABS
, call
->fptr
);
3560 s390_brasl (code
, s390_r14
, 0);
3565 case OP_VOIDCALL_REG
:
3567 s390_lr (code
, s390_r1
, ins
->sreg1
);
3568 s390_basr (code
, s390_r14
, s390_r1
);
3570 case OP_FCALL_MEMBASE
:
3571 case OP_LCALL_MEMBASE
:
3572 case OP_VCALL_MEMBASE
:
3573 case OP_VOIDCALL_MEMBASE
:
3574 case OP_CALL_MEMBASE
:
3575 s390_l (code
, s390_r1
, 0, ins
->sreg1
, ins
->inst_offset
);
3576 s390_basr (code
, s390_r14
, s390_r1
);
3579 g_assert_not_reached ();
3582 s390_lr (code
, s390_r1
, ins
->sreg1
);
3583 s390_ahi (code
, s390_r1
, 14);
3584 s390_srl (code
, s390_r1
, 0, 3);
3585 s390_sll (code
, s390_r1
, 0, 3);
3586 s390_l (code
, s390_r13
, 0, STK_BASE
, 0);
3587 s390_lcr (code
, s390_r1
, s390_r1
);
3588 s390_la (code
, STK_BASE
, STK_BASE
, s390_r1
, 0);
3589 s390_st (code
, s390_r13
, 0, STK_BASE
, 0);
3590 s390_la (code
, ins
->dreg
, 0, STK_BASE
, S390_MINIMAL_STACK_SIZE
+7);
3591 s390_srl (code
, ins
->dreg
, 0, 3);
3592 s390_sll (code
, ins
->dreg
, 0, 3);
3595 s390_br (code
, s390_r14
);
3598 s390_lr (code
, s390_r2
, ins
->sreg1
);
3599 mono_add_patch_info (cfg
, code
-cfg
->native_code
, MONO_PATCH_INFO_INTERNAL_METHOD
,
3600 (gpointer
)"mono_arch_throw_exception");
3601 s390_brasl (code
, s390_r14
, 0);
3604 case OP_START_HANDLER
:
3605 s390_lr (code
, s390_r0
, s390_r14
);
3606 s390_st (code
, s390_r0
, 0, ins
->inst_left
->inst_basereg
, ins
->inst_left
->inst_offset
);
3609 if (ins
->sreg1
!= s390_r2
)
3610 s390_lr (code
, s390_r2
, ins
->sreg1
);
3611 s390_l (code
, STK_BASE
, 0, STK_BASE
, 0);
3612 s390_lm (code
, s390_r6
, s390_r14
, STK_BASE
, S390_REG_SAVE_OFFSET
);
3613 s390_br (code
, s390_r14
);
3615 case CEE_ENDFINALLY
:
3616 s390_l (code
, s390_r14
, 0, ins
->inst_left
->inst_basereg
, ins
->inst_left
->inst_offset
);
3617 s390_br (code
, s390_r14
);
3619 case OP_CALL_HANDLER
:
3620 mono_add_patch_info (cfg
, code
-cfg
->native_code
,
3621 MONO_PATCH_INFO_BB
, ins
->inst_target_bb
);
3622 s390_brasl (code
, s390_r14
, 0);
3625 ins
->inst_c0
= code
- cfg
->native_code
;
3628 EMIT_UNCOND_BRANCH(ins
);
3631 s390_br (code
, ins
->sreg1
);
3634 s390_lhi (code
, ins
->dreg
, 1);
3636 s390_lhi (code
, ins
->dreg
, 0);
3639 s390_lhi (code
, ins
->dreg
, 1);
3641 s390_lhi (code
, ins
->dreg
, 0);
3644 s390_lhi (code
, ins
->dreg
, 1);
3646 s390_lhi (code
, ins
->dreg
, 0);
3649 s390_lhi (code
, ins
->dreg
, 1);
3651 s390_lhi (code
, ins
->dreg
, 0);
3654 s390_lhi (code
, ins
->dreg
, 1);
3656 s390_lhi (code
, ins
->dreg
, 0);
3658 case OP_COND_EXC_EQ
:
3659 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_EQ
, ins
->inst_p1
);
3661 case OP_COND_EXC_NE_UN
:
3662 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_NE
, ins
->inst_p1
);
3664 case OP_COND_EXC_LT
:
3665 case OP_COND_EXC_LT_UN
:
3666 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_LT
, ins
->inst_p1
);
3668 case OP_COND_EXC_GT
:
3669 case OP_COND_EXC_GT_UN
:
3670 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_GT
, ins
->inst_p1
);
3672 case OP_COND_EXC_GE
:
3673 case OP_COND_EXC_GE_UN
:
3674 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_GE
, ins
->inst_p1
);
3676 case OP_COND_EXC_LE
:
3677 case OP_COND_EXC_LE_UN
:
3678 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_LE
, ins
->inst_p1
);
3680 case OP_COND_EXC_OV
:
3681 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_OV
, ins
->inst_p1
);
3683 case OP_COND_EXC_NO
:
3684 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_NO
, ins
->inst_p1
);
3687 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_CY
, ins
->inst_p1
);
3689 case OP_COND_EXC_NC
:
3690 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_NC
, ins
->inst_p1
);
3693 EMIT_COND_BRANCH (ins
, S390_CC_EQ
);
3696 EMIT_COND_BRANCH (ins
, S390_CC_NE
);
3700 EMIT_COND_BRANCH (ins
, S390_CC_LT
);
3704 EMIT_COND_BRANCH (ins
, S390_CC_GT
);
3708 EMIT_COND_BRANCH (ins
, S390_CC_GE
);
3712 EMIT_COND_BRANCH (ins
, S390_CC_LE
);
3715 /* floating point opcodes */
3717 if (*((float *) ins
->inst_p0
) == 0) {
3718 s390_lzdr (code
, ins
->dreg
);
3720 s390_basr (code
, s390_r13
, 0);
3722 s390_word (code
, ins
->inst_p0
);
3723 s390_l (code
, s390_r13
, 0, s390_r13
, 4);
3724 s390_ld (code
, ins
->dreg
, 0, s390_r13
, 0);
3728 if (*((float *) ins
->inst_p0
) == 0) {
3729 s390_lzer (code
, ins
->dreg
);
3731 s390_basr (code
, s390_r13
, 0);
3733 s390_word (code
, ins
->inst_p0
);
3734 s390_l (code
, s390_r13
, 0, s390_r13
, 4);
3735 s390_le (code
, ins
->dreg
, 0, s390_r13
, 0);
3736 s390_ldebr(code
, ins
->dreg
, ins
->dreg
);
3739 case OP_STORER8_MEMBASE_REG
:
3740 if (s390_is_uimm12(ins
->inst_offset
)) {
3741 s390_std (code
, ins
->sreg1
, 0, ins
->inst_destbasereg
, ins
->inst_offset
);
3743 s390_basr (code
, s390_r13
, 0);
3745 s390_word (code
, ins
->inst_offset
);
3746 s390_l (code
, s390_r13
, 0, s390_r13
, 4);
3747 s390_std (code
, ins
->sreg1
, s390_r13
, ins
->inst_destbasereg
, 0);
3750 case OP_LOADR8_MEMBASE
:
3751 if (s390_is_uimm12(ins
->inst_offset
)) {
3752 s390_ld (code
, ins
->dreg
, 0, ins
->inst_basereg
, ins
->inst_offset
);
3754 s390_basr (code
, s390_r13
, 0);
3756 s390_word (code
, ins
->inst_offset
);
3757 s390_l (code
, s390_r13
, 0, s390_r13
, 4);
3758 s390_ld (code
, ins
->dreg
, s390_r13
, ins
->inst_basereg
, 0);
3761 case OP_STORER4_MEMBASE_REG
:
3762 if (s390_is_uimm12(ins
->inst_offset
)) {
3763 s390_ledbr(code
, s390_f0
, ins
->sreg1
);
3764 s390_ste (code
, s390_f0
, 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_ledbr(code
, s390_f0
, ins
->sreg1
);
3771 s390_ste (code
, s390_f0
, s390_r13
, ins
->inst_destbasereg
, 0);
3774 case OP_LOADR4_MEMBASE
:
3775 if (s390_is_uimm12(ins
->inst_offset
)) {
3776 s390_le (code
, ins
->dreg
, 0, ins
->inst_basereg
, ins
->inst_offset
);
3778 s390_basr (code
, s390_r13
, 0);
3780 s390_word (code
, ins
->inst_offset
);
3781 s390_l (code
, s390_r13
, 0, s390_r13
, 4);
3782 s390_le (code
, ins
->dreg
, s390_r13
, ins
->inst_basereg
, 0);
3784 s390_ldebr (code
, ins
->dreg
, ins
->dreg
);
3787 s390_cdfbr (code
, ins
->dreg
, ins
->sreg1
);
3788 s390_ltr (code
, ins
->sreg1
, ins
->sreg1
);
3789 s390_jnl (code
, 12);
3790 s390_basr (code
, s390_r13
, 0);
3792 s390_word (code
, 0x41f00000);
3793 s390_word (code
, 0);
3794 s390_adb (code
, ins
->dreg
, 0, s390_r13
, 4);
3797 s390_cefbr (code
, ins
->dreg
, ins
->sreg1
);
3800 s390_cdfbr (code
, ins
->dreg
, ins
->sreg1
);
3802 case OP_FCONV_TO_I1
:
3803 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 1, TRUE
);
3805 case OP_FCONV_TO_U1
:
3806 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 1, FALSE
);
3808 case OP_FCONV_TO_I2
:
3809 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 2, TRUE
);
3811 case OP_FCONV_TO_U2
:
3812 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 2, FALSE
);
3814 case OP_FCONV_TO_I4
:
3816 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 4, TRUE
);
3818 case OP_FCONV_TO_U4
:
3820 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 4, FALSE
);
3822 case OP_FCONV_TO_I8
:
3823 case OP_FCONV_TO_U8
:
3824 g_assert_not_reached ();
3825 /* Implemented as helper calls */
3827 case OP_LCONV_TO_R_UN
:
3828 g_assert_not_reached ();
3829 /* Implemented as helper calls */
3831 case OP_LCONV_TO_OVF_I
: {
3832 /* Valid ints: 0xffffffff:8000000 to 00000000:0x7f000000 */
3834 s390_ltr (code
, ins
->sreg2
, ins
->sreg2
);
3835 s390_jnl (code
, 0); CODEPTR(code
, o
[0]);
3836 s390_ltr (code
, ins
->sreg1
, ins
->sreg1
);
3837 s390_jnl (code
, 0); CODEPTR(code
, o
[1]);
3838 s390_lhi (code
, s390_r13
, -1);
3839 s390_cr (code
, ins
->sreg1
, s390_r13
);
3840 s390_jnz (code
, 0); CODEPTR(code
, o
[2]);
3841 if (ins
->dreg
!= ins
->sreg2
)
3842 s390_lr (code
, ins
->dreg
, ins
->sreg2
);
3843 s390_j (code
, 0); CODEPTR(code
, o
[3]);
3844 PTRSLOT(code
, o
[0]);
3845 s390_jz (code
, 0); CODEPTR(code
, o
[4]);
3846 PTRSLOT(code
, o
[1]);
3847 PTRSLOT(code
, o
[2]);
3848 mono_add_patch_info (cfg
, code
- cfg
->native_code
,
3849 MONO_PATCH_INFO_EXC
, "OverflowException");
3850 s390_brasl (code
, s390_r14
, 0);
3851 PTRSLOT(code
, o
[3]);
3852 PTRSLOT(code
, o
[4]);
3856 s390_sqdbr (code
, ins
->dreg
, ins
->sreg1
);
3859 if (ins
->dreg
== ins
->sreg1
)
3860 s390_adbr (code
, ins
->dreg
, ins
->sreg2
);
3862 if (ins
->dreg
== ins
->sreg2
)
3863 s390_adbr (code
, ins
->dreg
, ins
->sreg1
);
3865 s390_ldr (code
, ins
->dreg
, ins
->sreg1
);
3866 s390_adbr (code
, ins
->dreg
, ins
->sreg2
);
3871 if (ins
->dreg
== ins
->sreg1
)
3872 s390_sdbr (code
, ins
->dreg
, ins
->sreg2
);
3874 s390_ldr (code
, ins
->dreg
, ins
->sreg1
);
3875 s390_sdbr (code
, ins
->dreg
, ins
->sreg2
);
3879 if (ins
->dreg
== ins
->sreg1
)
3880 s390_mdbr (code
, ins
->dreg
, ins
->sreg2
);
3882 if (ins
->dreg
== ins
->sreg2
)
3883 s390_mdbr (code
, ins
->dreg
, ins
->sreg1
);
3885 s390_ldr (code
, ins
->dreg
, ins
->sreg1
);
3886 s390_mdbr (code
, ins
->dreg
, ins
->sreg2
);
3891 if (ins
->dreg
== ins
->sreg1
)
3892 s390_ddbr (code
, ins
->dreg
, ins
->sreg2
);
3894 s390_ldr (code
, ins
->dreg
, ins
->sreg1
);
3895 s390_ddbr (code
, ins
->dreg
, ins
->sreg2
);
3899 s390_lcdbr (code
, ins
->dreg
, ins
->sreg1
);
3902 if (ins
->dreg
!= ins
->sreg1
) {
3903 s390_ldr (code
, ins
->dreg
, ins
->sreg1
);
3905 s390_didbr (code
, ins
->dreg
, ins
->sreg2
, 5, s390_f15
);
3908 s390_cdbr (code
, ins
->sreg1
, ins
->sreg2
);
3911 s390_cdbr (code
, ins
->sreg1
, ins
->sreg2
);
3912 s390_lhi (code
, ins
->dreg
, 1);
3914 s390_lhi (code
, ins
->dreg
, 0);
3917 s390_cdbr (code
, ins
->sreg1
, ins
->sreg2
);
3918 s390_lhi (code
, ins
->dreg
, 1);
3920 s390_lhi (code
, ins
->dreg
, 0);
3923 s390_cdbr (code
, ins
->sreg1
, ins
->sreg2
);
3924 s390_lhi (code
, ins
->dreg
, 1);
3926 s390_lhi (code
, ins
->dreg
, 0);
3929 s390_cdbr (code
, ins
->sreg1
, ins
->sreg2
);
3930 s390_lhi (code
, ins
->dreg
, 1);
3932 s390_lhi (code
, ins
->dreg
, 0);
3935 s390_cdbr (code
, ins
->sreg1
, ins
->sreg2
);
3936 s390_lhi (code
, ins
->dreg
, 1);
3938 s390_lhi (code
, ins
->dreg
, 0);
3941 EMIT_COND_BRANCH (ins
, S390_CC_EQ
|S390_CC_OV
);
3944 EMIT_COND_BRANCH (ins
, S390_CC_NE
|S390_CC_OV
);
3947 EMIT_COND_BRANCH (ins
, S390_CC_LT
);
3950 EMIT_COND_BRANCH (ins
, S390_CC_LT
|S390_CC_OV
);
3953 EMIT_COND_BRANCH (ins
, S390_CC_GT
);
3956 EMIT_COND_BRANCH (ins
, S390_CC_GT
|S390_CC_OV
);
3959 EMIT_COND_BRANCH (ins
, S390_CC_GE
);
3962 EMIT_COND_BRANCH (ins
, S390_CC_GE
|S390_CC_OV
);
3965 EMIT_COND_BRANCH (ins
, S390_CC_LE
);
3968 EMIT_COND_BRANCH (ins
, S390_CC_LE
|S390_CC_OV
);
3970 case CEE_CKFINITE
: {
3972 s390_lhi (code
, s390_r13
, 0xfc0);
3973 s390_tcdb (code
, ins
->sreg1
, 0, s390_r13
, 0);
3974 s390_jz (code
, 0); CODEPTR(code
, o
);
3975 mono_add_patch_info (cfg
, code
- cfg
->native_code
+ 2,
3976 MONO_PATCH_INFO_EXC
, "ArithmeticException");
3977 s390_brasl (code
, s390_r14
,0);
3982 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins
->opcode
), __FUNCTION__
);
3983 g_assert_not_reached ();
3986 if ((cfg
->opt
& MONO_OPT_BRANCH
) && ((code
- cfg
->native_code
- offset
) > max_len
)) {
3987 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
3988 mono_inst_name (ins
->opcode
), max_len
, code
- cfg
->native_code
- offset
);
3989 g_assert_not_reached ();
3995 last_offset
= offset
;
4000 cfg
->code_len
= code
- cfg
->native_code
;
4003 /*========================= End of Function ========================*/
4005 /*------------------------------------------------------------------*/
4007 /* Name - mono_arch_register_lowlevel_calls */
4009 /* Function - Register routines to help with --trace operation. */
4011 /*------------------------------------------------------------------*/
4014 mono_arch_register_lowlevel_calls (void)
4016 mono_register_jit_icall (enter_method
, "mono_enter_method", NULL
, TRUE
);
4017 mono_register_jit_icall (leave_method
, "mono_leave_method", NULL
, TRUE
);
4020 /*========================= End of Function ========================*/
4022 /*------------------------------------------------------------------*/
4024 /* Name - mono_arch_patch_code */
4026 /* Function - Process the patch data created during the */
4027 /* instruction build process. This resolves jumps, */
4028 /* calls, variables etc. */
4030 /*------------------------------------------------------------------*/
4033 mono_arch_patch_code (MonoMethod
*method
, MonoDomain
*domain
, guint8
*code
, MonoJumpInfo
*ji
, gboolean run_cctors
)
4035 MonoJumpInfo
*patch_info
;
4037 for (patch_info
= ji
; patch_info
; patch_info
= patch_info
->next
) {
4038 unsigned char *ip
= patch_info
->ip
.i
+ code
;
4041 switch (patch_info
->type
) {
4042 case MONO_PATCH_INFO_BB
:
4043 target
= S390_RELATIVE((patch_info
->data
.bb
->native_offset
+code
),
4045 ip
+= 2; /* Skip over op-code */
4047 case MONO_PATCH_INFO_ABS
:
4048 target
= S390_RELATIVE(patch_info
->data
.target
, ip
);
4049 ip
+= 2; /* Skip over op-code */
4051 case MONO_PATCH_INFO_LABEL
:
4052 target
= S390_RELATIVE((patch_info
->data
.inst
->inst_c0
+code
),ip
);
4053 ip
+= 2; /* Skip over op-code */
4055 case MONO_PATCH_INFO_IP
:
4058 case MONO_PATCH_INFO_METHOD_REL
:
4059 g_assert_not_reached ();
4060 *((gpointer
*)(ip
)) = code
+ patch_info
->data
.offset
;
4062 case MONO_PATCH_INFO_INTERNAL_METHOD
: {
4063 MonoJitICallInfo
*mi
= mono_find_jit_icall_by_name (patch_info
->data
.name
);
4065 g_warning ("unknown MONO_PATCH_INFO_INTERNAL_METHOD %s", patch_info
->data
.name
);
4066 g_assert_not_reached ();
4068 target
= S390_RELATIVE(mono_icall_get_wrapper (mi
), ip
);
4069 ip
+= 2; /* Skip over op-code */
4072 case MONO_PATCH_INFO_METHOD_JUMP
:
4073 g_assert_not_reached ();
4075 case MONO_PATCH_INFO_METHOD
:
4076 if (patch_info
->data
.method
== method
) {
4077 target
= S390_RELATIVE(code
, ip
);
4079 /* get the trampoline to the method from the domain */
4080 target
= S390_RELATIVE(mono_arch_create_jit_trampoline (patch_info
->data
.method
), ip
);
4081 target
= mono_arch_create_jit_trampoline(patch_info
->data
.method
);
4082 target
= S390_RELATIVE(target
, ip
);
4084 ip
+= 2; /* Skip over op-code */
4086 case MONO_PATCH_INFO_SWITCH
: {
4087 gpointer
*table
= (gpointer
*)patch_info
->data
.target
;
4089 /*------------------------------------------------------*/
4090 /* ip is pointing at the basr r13,0/j +4 instruction */
4091 /* the vtable value follows this (i.e. ip+6) */
4092 /*------------------------------------------------------*/
4093 *((gconstpointer
*)(ip
+6)) = table
;
4095 for (i
= 0; i
< patch_info
->table_size
; i
++) {
4096 table
[i
] = (int)patch_info
->data
.table
[i
] + code
;
4100 case MONO_PATCH_INFO_METHODCONST
:
4101 case MONO_PATCH_INFO_CLASS
:
4102 case MONO_PATCH_INFO_IMAGE
:
4103 case MONO_PATCH_INFO_FIELD
:
4104 target
= S390_RELATIVE(patch_info
->data
.target
, ip
);
4106 case MONO_PATCH_INFO_R4
:
4107 case MONO_PATCH_INFO_R8
:
4108 g_assert_not_reached ();
4109 *((gconstpointer
*)(ip
+ 2)) = patch_info
->data
.target
;
4111 case MONO_PATCH_INFO_IID
:
4112 mono_class_init (patch_info
->data
.klass
);
4113 target
= S390_RELATIVE(patch_info
->data
.klass
->interface_id
, ip
);
4115 case MONO_PATCH_INFO_VTABLE
:
4116 target
= S390_RELATIVE(mono_class_vtable (domain
, patch_info
->data
.klass
),ip
);
4119 case MONO_PATCH_INFO_CLASS_INIT
:
4120 target
= S390_RELATIVE(mono_create_class_init_trampoline (mono_class_vtable (domain
, patch_info
->data
.klass
)), ip
);
4123 case MONO_PATCH_INFO_SFLDA
: {
4124 MonoVTable
*vtable
= mono_class_vtable (domain
, patch_info
->data
.field
->parent
);
4125 if (!vtable
->initialized
&& !(vtable
->klass
->flags
& TYPE_ATTRIBUTE_BEFORE_FIELD_INIT
) && mono_class_needs_cctor_run (vtable
->klass
, method
))
4126 /* Done by the generated code */
4130 mono_runtime_class_init (vtable
);
4132 target
= S390_RELATIVE((char*)vtable
->data
+ patch_info
->data
.field
->offset
, ip
);
4136 case MONO_PATCH_INFO_EXC_NAME
:
4137 *((gconstpointer
*)(ip
)) = patch_info
->data
.name
;
4139 case MONO_PATCH_INFO_LDSTR
:
4140 target
= mono_ldstr (domain
, patch_info
->data
.token
->image
,
4141 mono_metadata_token_index (patch_info
->data
.token
->token
));
4143 case MONO_PATCH_INFO_TYPE_FROM_HANDLE
: {
4145 MonoClass
*handle_class
;
4147 handle
= mono_ldtoken (patch_info
->data
.token
->image
,
4148 patch_info
->data
.token
->token
,
4149 &handle_class
, NULL
);
4150 mono_class_init (handle_class
);
4151 mono_class_init (mono_class_from_mono_type (handle
));
4156 case MONO_PATCH_INFO_LDTOKEN
: {
4158 MonoClass
*handle_class
;
4160 handle
= mono_ldtoken (patch_info
->data
.token
->image
,
4161 patch_info
->data
.token
->token
,
4162 &handle_class
, NULL
);
4163 mono_class_init (handle_class
);
4168 case MONO_PATCH_INFO_EXC
:
4169 /* everything is dealt with at epilog output time */
4172 g_assert_not_reached ();
4174 s390_patch (ip
, target
);
4178 /*========================= End of Function ========================*/
4180 /*------------------------------------------------------------------*/
4182 /* Name - mono_arch_max_epilog_size */
4184 /* Function - Determine the maximum size of the epilog code. */
4186 /*------------------------------------------------------------------*/
4189 mono_arch_max_epilog_size (MonoCompile
*cfg
)
4191 int max_epilog_size
= 96;
4192 MonoJumpInfo
*patch_info
;
4194 if (cfg
->method
->save_lmf
)
4195 max_epilog_size
+= 128;
4197 if (mono_jit_trace_calls
!= NULL
)
4198 max_epilog_size
+= 128;
4200 if (cfg
->prof_options
& MONO_PROFILE_ENTER_LEAVE
)
4201 max_epilog_size
+= 128;
4203 /* count the number of exception infos */
4205 for (patch_info
= cfg
->patch_info
; patch_info
; patch_info
= patch_info
->next
) {
4206 if (patch_info
->type
== MONO_PATCH_INFO_EXC
)
4207 max_epilog_size
+= 26;
4210 return max_epilog_size
;
4213 /*========================= End of Function ========================*/
4215 /*------------------------------------------------------------------*/
4217 /* Name - mono_arch_emit_prolog */
4219 /* Function - Create the instruction sequence for a function */
4222 /*------------------------------------------------------------------*/
4225 mono_arch_emit_prolog (MonoCompile
*cfg
)
4227 MonoMethod
*method
= cfg
->method
;
4229 MonoMethodSignature
*sig
;
4231 int alloc_size
, pos
, max_offset
, i
, lmfOffset
;
4237 if (mono_jit_trace_calls
!= NULL
&& mono_trace_eval (method
))
4240 cfg
->code_size
= 256;
4241 cfg
->native_code
= code
= g_malloc (cfg
->code_size
);
4243 s390_stm (code
, s390_r6
, s390_r14
, STK_BASE
, S390_REG_SAVE_OFFSET
);
4245 if (cfg
->flags
& MONO_CFG_HAS_ALLOCA
) {
4246 cfg
->used_int_regs
|= 1 << 11;
4249 alloc_size
= cfg
->stack_offset
;
4251 // alloc_size += S390_TRACE_STACK_SIZE;
4253 /* reserve room to save return value */
4257 // alloc_size += pos;
4259 // if (method->save_lmf)
4260 // alloc_size += sizeof(MonoLMF);
4262 // alloc_size = S390_ALIGN(alloc_size, S390_STACK_ALIGNMENT);
4264 cfg
->stack_usage
= alloc_size
;
4265 s390_lr (code
, s390_r11
, STK_BASE
);
4266 if (s390_is_imm16 (-alloc_size
)) {
4267 s390_ahi (code
, STK_BASE
, -alloc_size
);
4269 int stackSize
= alloc_size
;
4270 while (stackSize
> 32767) {
4271 s390_ahi (code
, STK_BASE
, -32767);
4274 s390_ahi (code
, STK_BASE
, -stackSize
);
4276 s390_st (code
, s390_r11
, 0, STK_BASE
, 0);
4278 if (cfg
->flags
& MONO_CFG_HAS_ALLOCA
)
4279 s390_lr (code
, s390_r11
, STK_BASE
);
4281 /* compute max_offset in order to use short forward jumps
4282 * we always do it on s390 because the immediate displacement
4283 * for jumps is too small
4286 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
) {
4287 MonoInst
*ins
= bb
->code
;
4288 bb
->max_offset
= max_offset
;
4290 if (cfg
->prof_options
& MONO_PROFILE_COVERAGE
)
4294 max_offset
+= ((guint8
*)ins_spec
[ins
->opcode
])[MONO_INST_LEN
];
4299 /* load arguments allocated to register from the stack */
4300 sig
= method
->signature
;
4303 cinfo
= calculate_sizes (sig
, &sz
, sig
->pinvoke
);
4305 if (cinfo
->struct_ret
) {
4306 ArgInfo
*ainfo
= &cinfo
->ret
;
4308 inst
->unused
= ainfo
->vtsize
;
4309 s390_st (code
, ainfo
->reg
, 0, inst
->inst_basereg
, inst
->inst_offset
);
4312 for (i
= 0; i
< sig
->param_count
+ sig
->hasthis
; ++i
) {
4313 ArgInfo
*ainfo
= cinfo
->args
+ i
;
4314 inst
= cfg
->varinfo
[pos
];
4316 if (inst
->opcode
== OP_REGVAR
) {
4317 if (ainfo
->regtype
== RegTypeGeneral
)
4318 s390_lr (code
, inst
->dreg
, ainfo
->reg
);
4319 else if (ainfo
->regtype
== RegTypeFP
) {
4320 if (ainfo
->size
== 4) {
4321 s390_ledbr (code
, inst
->dreg
, ainfo
->reg
);
4323 s390_ldr (code
, inst
->dreg
, ainfo
->reg
);
4326 else if (ainfo
->regtype
== RegTypeBase
) {
4327 s390_lr (code
, s390_r13
, STK_BASE
);
4328 s390_ahi (code
, s390_r13
, alloc_size
);
4329 s390_l (code
, inst
->dreg
, 0, s390_r13
, ainfo
->offset
);
4331 g_assert_not_reached ();
4333 if (cfg
->verbose_level
> 2)
4334 g_print ("Argument %d assigned to register %s\n",
4335 pos
, mono_arch_regname (inst
->dreg
));
4337 if (ainfo
->regtype
== RegTypeGeneral
) {
4338 if (!((ainfo
->reg
>= 2) && (ainfo
->reg
<= 6)))
4339 g_assert_not_reached();
4340 switch (ainfo
->size
) {
4342 s390_stc (code
, ainfo
->reg
, 0, inst
->inst_basereg
, inst
->inst_offset
);
4345 s390_sth (code
, ainfo
->reg
, 0, inst
->inst_basereg
, inst
->inst_offset
);
4348 s390_stm (code
, ainfo
->reg
, ainfo
->reg
+ 1,
4349 inst
->inst_basereg
, inst
->inst_offset
);
4352 s390_st (code
, ainfo
->reg
, 0, inst
->inst_basereg
, inst
->inst_offset
);
4354 } else if (ainfo
->regtype
== RegTypeBase
) {
4355 } else if (ainfo
->regtype
== RegTypeFP
) {
4356 if (ainfo
->size
== 8)
4357 s390_std (code
, ainfo
->reg
, 0, inst
->inst_basereg
, inst
->inst_offset
);
4358 else if (ainfo
->size
== 4)
4359 s390_ste (code
, ainfo
->reg
, 0, inst
->inst_basereg
, inst
->inst_offset
);
4361 g_assert_not_reached ();
4362 } else if (ainfo
->regtype
== RegTypeStructByVal
) {
4363 int doffset
= inst
->inst_offset
;
4365 if (ainfo
->reg
!= STK_BASE
)
4369 s390_lr (code
, s390_r13
, STK_BASE
);
4370 s390_ahi (code
, s390_r13
, alloc_size
);
4372 switch (ainfo
->size
) {
4374 if (ainfo
->reg
== STK_BASE
)
4375 s390_ic (code
, reg
, 0, s390_r13
, ainfo
->offset
+3);
4376 s390_stc (code
, reg
, 0, inst
->inst_basereg
, doffset
);
4379 if (ainfo
->reg
== STK_BASE
)
4380 s390_lh (code
, reg
, 0, s390_r13
, ainfo
->offset
+2);
4381 s390_sth (code
, reg
, 0, inst
->inst_basereg
, doffset
);
4384 if (ainfo
->reg
== STK_BASE
)
4385 s390_l (code
, reg
, 0, s390_r13
, ainfo
->offset
);
4386 s390_st (code
, reg
, 0, inst
->inst_basereg
, doffset
);
4389 if (ainfo
->reg
== STK_BASE
)
4390 s390_lm (code
, s390_r0
, s390_r1
, s390_r13
, ainfo
->offset
);
4391 s390_stm (code
, reg
, reg
+1, inst
->inst_basereg
, doffset
);
4394 } else if (ainfo
->regtype
== RegTypeStructByAddr
) {
4395 code
= emit_memcpy (code
, ainfo
->vtsize
,
4396 inst
->inst_basereg
, inst
->inst_offset
, ainfo
->reg
, 0);
4398 g_assert_not_reached ();
4403 if (method
->save_lmf
) {
4404 /*---------------------------------------------------------------*/
4405 /* Preserve the parameter registers while we fix up the lmf */
4406 /*---------------------------------------------------------------*/
4407 s390_lr (code
, s390_r7
, s390_r2
);
4408 s390_lr (code
, s390_r8
, s390_r3
);
4409 s390_lr (code
, s390_r9
, s390_r4
);
4410 s390_lr (code
, s390_r10
, s390_r5
);
4412 mono_add_patch_info (cfg
, code
- cfg
->native_code
,
4413 MONO_PATCH_INFO_INTERNAL_METHOD
,
4414 (gpointer
)"mono_get_lmf_addr");
4415 /*---------------------------------------------------------------*/
4416 /* On return from this call r2 have the address of the &lmf */
4417 /*---------------------------------------------------------------*/
4418 s390_brasl (code
, s390_r14
, 0);
4420 /*---------------------------------------------------------------*/
4421 /* we build the MonoLMF structure on the stack - see mini-s390.h */
4422 /*---------------------------------------------------------------*/
4423 lmfOffset
= alloc_size
- sizeof(MonoLMF
);
4425 s390_lr (code
, s390_r13
, cfg
->frame_reg
);
4426 s390_ahi (code
, s390_r13
, lmfOffset
);
4428 /*---------------------------------------------------------------*/
4429 /* Set lmf.lmf_addr = jit_tls->lmf */
4430 /*---------------------------------------------------------------*/
4431 s390_st (code
, s390_r2
, 0, s390_r13
, G_STRUCT_OFFSET(MonoLMF
, lmf_addr
));
4433 /*---------------------------------------------------------------*/
4434 /* Get current lmf */
4435 /*---------------------------------------------------------------*/
4436 s390_l (code
, s390_r0
, 0, s390_r2
, 0);
4438 /*---------------------------------------------------------------*/
4439 /* Set our lmf as the current lmf */
4440 /*---------------------------------------------------------------*/
4441 s390_st (code
, s390_r13
, 0, s390_r2
, 0);
4443 /*---------------------------------------------------------------*/
4444 /* Have our lmf.previous_lmf point to the last lmf */
4445 /*---------------------------------------------------------------*/
4446 s390_st (code
, s390_r0
, 0, s390_r13
, G_STRUCT_OFFSET(MonoLMF
, previous_lmf
));
4448 /*---------------------------------------------------------------*/
4449 /* save method info */
4450 /*---------------------------------------------------------------*/
4451 s390_basr (code
, s390_r1
, 0);
4453 s390_word (code
, method
);
4454 s390_l (code
, s390_r1
, 0, s390_r1
, 4);
4455 s390_st (code
, s390_r1
, 0, s390_r13
, G_STRUCT_OFFSET(MonoLMF
, method
));
4457 /*---------------------------------------------------------------*/
4458 /* save the current IP */
4459 /*---------------------------------------------------------------*/
4460 s390_lr (code
, s390_r1
, cfg
->frame_reg
);
4461 s390_ahi (code
, s390_r1
, alloc_size
);
4462 s390_st (code
, s390_r1
, 0, s390_r13
, G_STRUCT_OFFSET(MonoLMF
, ebp
));
4463 s390_l (code
, s390_r1
, 0, s390_r1
, S390_RET_ADDR_OFFSET
);
4464 s390_la (code
, s390_r1
, 0, s390_r1
, 0);
4465 s390_st (code
, s390_r1
, 0, s390_r13
, G_STRUCT_OFFSET(MonoLMF
, eip
));
4467 /*---------------------------------------------------------------*/
4468 /* Restore the parameter registers now that we've set up the lmf */
4469 /*---------------------------------------------------------------*/
4470 s390_lr (code
, s390_r2
, s390_r7
);
4471 s390_lr (code
, s390_r3
, s390_r8
);
4472 s390_lr (code
, s390_r4
, s390_r9
);
4473 s390_lr (code
, s390_r5
, s390_r10
);
4477 code
= mono_arch_instrument_prolog (cfg
, enter_method
, code
, TRUE
);
4479 cfg
->code_len
= code
- cfg
->native_code
;
4485 /*========================= End of Function ========================*/
4487 /*------------------------------------------------------------------*/
4489 /* Name - mono_arch_emit_epilog */
4491 /* Function - Emit the instructions for a function epilog. */
4493 /*------------------------------------------------------------------*/
4496 mono_arch_emit_epilog (MonoCompile
*cfg
)
4498 MonoJumpInfo
*patch_info
;
4499 MonoMethod
*method
= cfg
->method
;
4500 MonoMethodSignature
*sig
= method
->signature
;
4502 int i
, lmfOffset
, tracing
= 0;
4505 code
= cfg
->native_code
+ cfg
->code_len
;
4507 if (mono_jit_trace_calls
!= NULL
&& mono_trace_eval (method
)) {
4508 code
= mono_arch_instrument_epilog (cfg
, leave_method
, code
, TRUE
);
4512 if (method
->save_lmf
) {
4513 s390_lr (code
, s390_r13
, cfg
->frame_reg
);
4515 lmfOffset
= cfg
->stack_usage
- sizeof(MonoLMF
);
4517 /*-------------------------------------------------*/
4519 /*-------------------------------------------------*/
4520 s390_ahi (code
, s390_r13
, lmfOffset
);
4522 /*-------------------------------------------------*/
4523 /* r6 = &jit_tls->lmf */
4524 /*-------------------------------------------------*/
4525 s390_l (code
, s390_r6
, 0, s390_r13
, G_STRUCT_OFFSET(MonoLMF
, lmf_addr
));
4527 /*-------------------------------------------------*/
4528 /* r0 = lmf.previous_lmf */
4529 /*-------------------------------------------------*/
4530 s390_l (code
, s390_r0
, 0, s390_r13
, G_STRUCT_OFFSET(MonoLMF
, previous_lmf
));
4532 /*-------------------------------------------------*/
4533 /* jit_tls->lmf = previous_lmf */
4534 /*-------------------------------------------------*/
4535 s390_l (code
, s390_r13
, 0, s390_r6
, 0);
4536 s390_st (code
, s390_r0
, 0, s390_r6
, 0);
4539 if (cfg
->frame_reg
!= STK_BASE
)
4540 s390_lr (code
, STK_BASE
, cfg
->frame_reg
);
4542 s390_ahi (code
, STK_BASE
, cfg
->stack_usage
);
4543 s390_lm (code
, s390_r6
, s390_r14
, STK_BASE
, S390_REG_SAVE_OFFSET
);
4544 s390_br (code
, s390_r14
);
4546 /* add code to raise exceptions */
4547 for (patch_info
= cfg
->patch_info
; patch_info
; patch_info
= patch_info
->next
) {
4548 switch (patch_info
->type
) {
4549 case MONO_PATCH_INFO_EXC
: {
4550 /*-----------------------------------------------------*/
4551 /* Patch the branch in epilog to come here */
4552 /*-----------------------------------------------------*/
4553 s390_patch (patch_info
->ip
.i
+cfg
->native_code
+2,
4554 S390_RELATIVE(code
,patch_info
->ip
.i
+cfg
->native_code
));
4555 /*-----------------------------------------------------*/
4556 /* Patch the parameter passed to the handler */
4557 /*-----------------------------------------------------*/
4558 s390_basr (code
, s390_r13
, 0);
4560 mono_add_patch_info (cfg
, code
- cfg
->native_code
,
4561 MONO_PATCH_INFO_EXC_NAME
,
4562 patch_info
->data
.target
);
4563 s390_word (code
, 0);
4564 /*-----------------------------------------------------*/
4565 /* Load the return address and the parameter register */
4566 /*-----------------------------------------------------*/
4567 s390_larl (code
, s390_r14
, S390_RELATIVE((patch_info
->ip
.i
+
4568 cfg
->native_code
+ 8), code
));
4569 s390_l (code
, s390_r2
, 0, s390_r13
, 4);
4570 /*-----------------------------------------------------*/
4571 /* Reuse the current patch to set the jump */
4572 /*-----------------------------------------------------*/
4573 patch_info
->type
= MONO_PATCH_INFO_INTERNAL_METHOD
;
4574 patch_info
->data
.name
= "mono_arch_throw_exception_by_name";
4575 patch_info
->ip
.i
= code
- cfg
->native_code
;
4576 s390_jcl (code
, S390_CC_UN
, 0);
4585 cfg
->code_len
= code
- cfg
->native_code
;
4587 g_assert (cfg
->code_len
< cfg
->code_size
);
4591 /*========================= End of Function ========================*/
4593 /*------------------------------------------------------------------*/
4595 /* Name - mono_arch_setup_jit_tls_data */
4597 /* Function - Setup the JIT's Thread Level Specific Data. */
4599 /*------------------------------------------------------------------*/
4602 mono_arch_setup_jit_tls_data (MonoJitTlsData
*tls
)
4606 /*========================= End of Function ========================*/
4608 /*------------------------------------------------------------------*/
4610 /* Name - mono_arch_free_jit_tls_data */
4612 /* Function - Free tls data. */
4614 /*------------------------------------------------------------------*/
4617 mono_arch_free_jit_tls_data (MonoJitTlsData
*tls
)
4621 /*========================= End of Function ========================*/
4623 /*------------------------------------------------------------------*/
4625 /* Name - mono_arch_emit_this_vret_args */
4629 /*------------------------------------------------------------------*/
4632 mono_arch_emit_this_vret_args (MonoCompile
*cfg
, MonoCallInst
*inst
, int this_reg
, int this_type
, int vt_reg
)
4634 int this_dreg
= s390_r2
;
4637 this_dreg
= s390_r3
;
4639 /* add the this argument */
4640 if (this_reg
!= -1) {
4642 MONO_INST_NEW (cfg
, this, OP_SETREG
);
4643 this->type
= this_type
;
4644 this->sreg1
= this_reg
;
4645 this->dreg
= this_dreg
;
4646 mono_bblock_add_inst (cfg
->cbb
, this);
4651 MONO_INST_NEW (cfg
, vtarg
, OP_SETREG
);
4652 vtarg
->type
= STACK_MP
;
4653 vtarg
->sreg1
= vt_reg
;
4654 vtarg
->dreg
= s390_r2
;
4655 mono_bblock_add_inst (cfg
->cbb
, vtarg
);
4659 /*========================= End of Function ========================*/
4661 /*------------------------------------------------------------------*/
4663 /* Name - mono_arch_get_opcode_for_method */
4665 /* Function - Check for opcodes we can handle directly in */
4668 /*------------------------------------------------------------------*/
4671 mono_arch_get_opcode_for_method (MonoCompile
*cfg
, MonoMethod
*cmethod
, MonoMethodSignature
*fsig
, MonoInst
**args
)
4673 if (cmethod
->klass
== mono_defaults
.math_class
) {
4674 if (strcmp (cmethod
->name
, "Sqrt") == 0)
4680 /*========================= End of Function ========================*/
4682 /*------------------------------------------------------------------*/
4684 /* Name - mono_arch_print_tree */
4686 /* Function - Print platform-specific opcode details. */
4688 /* Returns - 1 - opcode details have been printed */
4689 /* 0 - opcode details have not been printed */
4691 /*------------------------------------------------------------------*/
4694 mono_arch_print_tree (MonoInst
*tree
, int arity
)
4698 switch (tree
->opcode
) {
4699 case OP_S390_LOADARG
:
4700 case OP_S390_ARGPTR
:
4701 case OP_S390_STKARG
:
4702 printf ("[0x%x(%s)]", tree
->inst_offset
,
4703 mono_arch_regname (tree
->inst_basereg
));
4712 /*========================= End of Function ========================*/
4714 /*------------------------------------------------------------------*/
4716 /* Name - mono_arch_regalloc_cost */
4718 /* Function - Determine the cost, in the number of memory */
4719 /* references, of the action of allocating the var- */
4720 /* iable VMV into a register during global register */
4723 /* Returns - Cost */
4725 /*------------------------------------------------------------------*/
4728 mono_arch_regalloc_cost (MonoCompile
*cfg
, MonoMethodVar
*vmv
)
4734 /*========================= End of Function ========================*/