Replace string/hash-based MONO_PATCH_INFO_JIT_ICALL with enum-based MONO_PATCH_INFO_J...
[mono-project.git] / mono / mini / mini-s390x.c
blob97f31583468e487bced81a50fc45310e72d2c54f
1 /**
2 * \file
3 * Function - S/390 backend for the Mono code generator.
5 * Name - Neale Ferguson (Neale.Ferguson@SoftwareAG-usa.com)
7 * Date - January, 2004
9 * Derivation - From mini-x86 & mini-ppc by -
10 * Paolo Molaro (lupus@ximian.com)
11 * Dietmar Maurer (dietmar@ximian.com)
15 /*------------------------------------------------------------------*/
16 /* D e f i n e s */
17 /*------------------------------------------------------------------*/
19 #define MAX_ARCH_DELEGATE_PARAMS 7
21 #define EMIT_COND_BRANCH(ins,cond) \
22 { \
23 if (ins->inst_true_bb->native_offset) { \
24 int displace; \
25 displace = ((cfg->native_code + \
26 ins->inst_true_bb->native_offset) - code) / 2; \
27 if (s390_is_imm16(displace)) { \
28 s390_brc (code, cond, displace); \
29 } else { \
30 s390_jcl (code, cond, displace); \
31 } \
32 } else { \
33 mono_add_patch_info (cfg, code - cfg->native_code, \
34 MONO_PATCH_INFO_BB, ins->inst_true_bb); \
35 s390_jcl (code, cond, 0); \
36 } \
39 #define EMIT_UNCOND_BRANCH(ins) \
40 { \
41 if (ins->inst_target_bb->native_offset) { \
42 int displace; \
43 displace = ((cfg->native_code + \
44 ins->inst_target_bb->native_offset) - code) / 2; \
45 if (s390_is_imm16(displace)) { \
46 s390_brc (code, S390_CC_UN, displace); \
47 } else { \
48 s390_jcl (code, S390_CC_UN, displace); \
49 } \
50 } else { \
51 mono_add_patch_info (cfg, code - cfg->native_code, \
52 MONO_PATCH_INFO_BB, ins->inst_target_bb); \
53 s390_jcl (code, S390_CC_UN, 0); \
54 } \
57 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) \
58 do { \
59 mono_add_patch_info (cfg, code - cfg->native_code, \
60 MONO_PATCH_INFO_EXC, exc_name); \
61 s390_jcl (code, cond, 0); \
62 } while (0);
64 #define EMIT_COMP_AND_BRANCH(ins, cab, cmp) \
65 { \
66 if (ins->inst_true_bb->native_offset) { \
67 int displace; \
68 displace = ((cfg->native_code + \
69 ins->inst_true_bb->native_offset) - code) / 2; \
70 if (s390_is_imm16(displace)) { \
71 s390_##cab (code, ins->sreg1, ins->sreg2, \
72 ins->sreg3, displace); \
73 } else { \
74 s390_##cmp (code, ins->sreg1, ins->sreg2); \
75 displace = ((cfg->native_code + \
76 ins->inst_true_bb->native_offset) - code) / 2; \
77 s390_jcl (code, ins->sreg3, displace); \
78 } \
79 } else { \
80 s390_##cmp (code, ins->sreg1, ins->sreg2); \
81 mono_add_patch_info (cfg, code - cfg->native_code, \
82 MONO_PATCH_INFO_BB, ins->inst_true_bb); \
83 s390_jcl (code, ins->sreg3, 0); \
84 } \
87 #define EMIT_COMP_AND_BRANCH_IMM(ins, cab, cmp, lat, logical) \
88 { \
89 if (ins->inst_true_bb->native_offset) { \
90 int displace; \
91 if ((ins->backend.data == 0) && (!logical)) { \
92 s390_##lat (code, ins->sreg1, ins->sreg1); \
93 displace = ((cfg->native_code + \
94 ins->inst_true_bb->native_offset) - code) / 2; \
95 if (s390_is_imm16(displace)) { \
96 s390_brc (code, ins->sreg3, displace); \
97 } else { \
98 s390_jcl (code, ins->sreg3, displace); \
99 } \
100 } else { \
101 S390_SET (code, s390_r0, ins->backend.data); \
102 displace = ((cfg->native_code + \
103 ins->inst_true_bb->native_offset) - code) / 2; \
104 if (s390_is_imm16(displace)) { \
105 s390_##cab (code, ins->sreg1, s390_r0, \
106 ins->sreg3, displace); \
107 } else { \
108 s390_##cmp (code, ins->sreg1, s390_r0); \
109 displace = ((cfg->native_code + \
110 ins->inst_true_bb->native_offset) - code) / 2; \
111 s390_jcl (code, ins->sreg3, displace); \
114 } else { \
115 if ((ins->backend.data == 0) && (!logical)) { \
116 s390_##lat (code, ins->sreg1, ins->sreg1); \
117 } else { \
118 S390_SET (code, s390_r0, ins->backend.data); \
119 s390_##cmp (code, ins->sreg1, s390_r0); \
121 mono_add_patch_info (cfg, code - cfg->native_code, \
122 MONO_PATCH_INFO_BB, ins->inst_true_bb); \
123 s390_jcl (code, ins->sreg3, 0); \
127 #define CHECK_SRCDST_COM \
128 if (ins->dreg == ins->sreg2) { \
129 src2 = ins->sreg1; \
130 } else { \
131 src2 = ins->sreg2; \
132 if (ins->dreg != ins->sreg1) { \
133 s390_lgr (code, ins->dreg, ins->sreg1); \
137 #define CHECK_SRCDST_NCOM \
138 if (ins->dreg == ins->sreg2) { \
139 src2 = s390_r13; \
140 s390_lgr (code, s390_r13, ins->sreg2); \
141 } else { \
142 src2 = ins->sreg2; \
144 if (ins->dreg != ins->sreg1) { \
145 s390_lgr (code, ins->dreg, ins->sreg1); \
148 #define CHECK_SRCDST_COM_I \
149 if (ins->dreg == ins->sreg2) { \
150 src2 = ins->sreg1; \
151 } else { \
152 src2 = ins->sreg2; \
153 if (ins->dreg != ins->sreg1) { \
154 s390_lgfr (code, ins->dreg, ins->sreg1); \
158 #define CHECK_SRCDST_NCOM_I \
159 if (ins->dreg == ins->sreg2) { \
160 src2 = s390_r13; \
161 s390_lgfr (code, s390_r13, ins->sreg2); \
162 } else { \
163 src2 = ins->sreg2; \
165 if (ins->dreg != ins->sreg1) { \
166 s390_lgfr (code, ins->dreg, ins->sreg1); \
169 #define CHECK_SRCDST_COM_F \
170 if (ins->dreg == ins->sreg2) { \
171 src2 = ins->sreg1; \
172 } else { \
173 src2 = ins->sreg2; \
174 if (ins->dreg != ins->sreg1) { \
175 s390_ldr (code, ins->dreg, ins->sreg1); \
179 #define CHECK_SRCDST_NCOM_F \
180 if (ins->dreg == ins->sreg2) { \
181 src2 = s390_f15; \
182 s390_ldr (code, s390_r13, ins->sreg2); \
183 } else { \
184 src2 = ins->sreg2; \
186 if (ins->dreg != ins->sreg1) { \
187 s390_ldr (code, ins->dreg, ins->sreg1); \
190 #define MONO_EMIT_NEW_MOVE(cfg,dest,offset,src,imm,size) do { \
191 MonoInst *inst; \
192 int sReg, dReg; \
193 MONO_INST_NEW (cfg, inst, OP_NOP); \
194 if (size > 256) { \
195 inst->dreg = dest; \
196 inst->inst_offset = offset; \
197 inst->sreg1 = src; \
198 inst->inst_imm = imm; \
199 } else { \
200 if (s390_is_uimm12(offset)) { \
201 inst->dreg = dest; \
202 inst->inst_offset = offset; \
203 } else { \
204 dReg = mono_alloc_preg (cfg); \
205 MONO_EMIT_NEW_BIALU_IMM(cfg, OP_ADD_IMM, \
206 dReg, dest, offset); \
207 inst->dreg = dReg; \
208 inst->inst_offset = 0; \
210 if (s390_is_uimm12(imm)) { \
211 inst->sreg1 = src; \
212 inst->inst_imm = imm; \
213 } else { \
214 sReg = mono_alloc_preg (cfg); \
215 MONO_EMIT_NEW_BIALU_IMM(cfg, OP_ADD_IMM, \
216 sReg, src, imm); \
217 inst->sreg1 = sReg; \
218 inst->inst_imm = 0; \
221 inst->opcode = OP_S390_MOVE; \
222 inst->backend.size = size; \
223 MONO_ADD_INS (cfg->cbb, inst); \
224 } while (0)
226 #define MONO_OUTPUT_VTR(cfg, size, dr, sr, so) do { \
227 int reg = mono_alloc_preg (cfg); \
228 switch (size) { \
229 case 0: \
230 MONO_EMIT_NEW_ICONST(cfg, reg, 0); \
231 break; \
232 case 1: \
233 MONO_EMIT_NEW_LOAD_MEMBASE_OP(cfg, OP_LOADU1_MEMBASE, \
234 reg, sr, so); \
235 break; \
236 case 2: \
237 MONO_EMIT_NEW_LOAD_MEMBASE_OP(cfg, OP_LOADU2_MEMBASE, \
238 reg, sr, so); \
239 break; \
240 case 4: \
241 MONO_EMIT_NEW_LOAD_MEMBASE_OP(cfg, OP_LOADI4_MEMBASE, \
242 reg, sr, so); \
243 break; \
244 case 8: \
245 MONO_EMIT_NEW_LOAD_MEMBASE_OP(cfg, OP_LOADI8_MEMBASE, \
246 reg, sr, so); \
247 break; \
249 mono_call_inst_add_outarg_reg(cfg, call, reg, dr, FALSE); \
250 } while (0)
252 #define MONO_OUTPUT_VTS(cfg, size, dr, dx, sr, so) do { \
253 int tmpr; \
254 switch (size) { \
255 case 0: \
256 tmpr = mono_alloc_preg (cfg); \
257 MONO_EMIT_NEW_ICONST(cfg, tmpr, 0); \
258 MONO_EMIT_NEW_STORE_MEMBASE(cfg, OP_STORE_MEMBASE_REG, \
259 dr, dx, tmpr); \
260 break; \
261 case 1: \
262 tmpr = mono_alloc_preg (cfg); \
263 MONO_EMIT_NEW_LOAD_MEMBASE_OP(cfg, OP_LOADU1_MEMBASE, \
264 tmpr, sr, so); \
265 MONO_EMIT_NEW_STORE_MEMBASE(cfg, OP_STORE_MEMBASE_REG, \
266 dr, dx, tmpr); \
267 break; \
268 case 2: \
269 tmpr = mono_alloc_preg (cfg); \
270 MONO_EMIT_NEW_LOAD_MEMBASE_OP(cfg, OP_LOADU2_MEMBASE, \
271 tmpr, sr, so); \
272 MONO_EMIT_NEW_STORE_MEMBASE(cfg, OP_STORE_MEMBASE_REG, \
273 dr, dx, tmpr); \
274 break; \
275 case 4: \
276 tmpr = mono_alloc_preg (cfg); \
277 MONO_EMIT_NEW_LOAD_MEMBASE_OP(cfg, OP_LOADI4_MEMBASE, \
278 tmpr, sr, so); \
279 MONO_EMIT_NEW_STORE_MEMBASE(cfg, OP_STORE_MEMBASE_REG, \
280 dr, dx, tmpr); \
281 break; \
282 case 8: \
283 MONO_EMIT_NEW_MOVE (cfg, dr, dx, sr, so, size); \
284 break; \
286 } while (0)
288 #undef DEBUG
289 #define DEBUG(a) if (cfg->verbose_level > 1) a
291 #define MAX_EXC 16
293 #define S390_TRACE_STACK_SIZE (5*sizeof(gpointer)+4*sizeof(gdouble))
295 #define BREAKPOINT_SIZE sizeof(breakpoint_t)
296 #define S390X_NOP_SIZE sizeof(RR_Format)
298 #define MAX(a, b) ((a) > (b) ? (a) : (b))
301 * imt trampoline size values
303 #define CMP_SIZE 24
304 #define LOADCON_SIZE 20
305 #define LOAD_SIZE 6
306 #define BR_SIZE 2
307 #define JUMP_SIZE 6
308 #define ENABLE_WRONG_METHOD_CHECK 0
310 #define mono_mini_arch_lock() mono_os_mutex_lock (&mini_arch_mutex)
311 #define mono_mini_arch_unlock() mono_os_mutex_unlock (&mini_arch_mutex)
313 /*========================= End of Defines =========================*/
315 /*------------------------------------------------------------------*/
316 /* I n c l u d e s */
317 /*------------------------------------------------------------------*/
319 #include "mini.h"
320 #include <string.h>
321 #include <sys/types.h>
322 #include <unistd.h>
324 #include <mono/metadata/abi-details.h>
325 #include <mono/metadata/appdomain.h>
326 #include <mono/metadata/debug-helpers.h>
327 #include <mono/metadata/profiler-private.h>
328 #include <mono/utils/mono-error.h>
329 #include <mono/utils/mono-error-internals.h>
330 #include <mono/utils/mono-math.h>
331 #include <mono/utils/mono-mmap.h>
332 #include <mono/utils/mono-hwcap.h>
333 #include <mono/utils/mono-threads.h>
334 #include <mono/utils/unlocked.h>
336 #include "mini-s390x.h"
337 #include "cpu-s390x.h"
338 #include "support-s390x.h"
339 #include "jit-icalls.h"
340 #include "ir-emit.h"
341 #include "mini-gc.h"
342 #include "aot-runtime.h"
343 #include "mini-runtime.h"
345 /*========================= End of Includes ========================*/
347 /*------------------------------------------------------------------*/
348 /* T y p e d e f s */
349 /*------------------------------------------------------------------*/
351 typedef struct {
352 guint stack_size,
353 local_size,
354 code_size,
355 parm_size,
356 offset,
357 offStruct,
358 retStruct;
359 } size_data;
361 typedef struct InstList InstList;
363 struct InstList {
364 InstList *prev;
365 InstList *next;
366 MonoInst *data;
369 typedef enum {
370 RegTypeGeneral,
371 RegTypeBase,
372 RegTypeFP,
373 RegTypeFPR4,
374 RegTypeStructByVal,
375 RegTypeStructByValInFP,
376 RegTypeStructByAddr,
377 RegTypeStructByAddrOnStack
378 } ArgStorage;
380 typedef struct {
381 gint32 offset; /* offset from caller's stack */
382 gint32 offparm; /* offset from callee's stack */
383 guint16 vtsize; /* in param area */
384 guint8 reg;
385 ArgStorage regtype;
386 guint32 size; /* Size of structure used by RegTypeStructByVal */
387 gint32 type; /* Data type of argument */
388 } ArgInfo;
390 struct CallInfo {
391 int nargs;
392 int lastgr;
393 guint32 stack_usage;
394 guint32 struct_ret;
395 ArgInfo ret;
396 ArgInfo sigCookie;
397 size_data sz;
398 int vret_arg_index;
399 MonoMethodSignature *sig;
400 ArgInfo args [1];
403 typedef struct {
404 gint64 gr[5]; /* R2-R6 */
405 gdouble fp[3]; /* F0-F2 */
406 } __attribute__ ((__packed__)) RegParm;
408 typedef struct {
409 RR_Format basr;
410 RI_Format j;
411 void *pTrigger;
412 RXY_Format lg;
413 RXY_Format trigger;
414 } __attribute__ ((__packed__)) breakpoint_t;
416 /*========================= End of Typedefs ========================*/
418 /*------------------------------------------------------------------*/
419 /* P r o t o t y p e s */
420 /*------------------------------------------------------------------*/
422 static void indent (int);
423 static guint8 * backUpStackPtr(MonoCompile *, guint8 *);
424 static inline void add_general (guint *, size_data *, ArgInfo *);
425 static inline void add_stackParm (guint *, size_data *, ArgInfo *, gint);
426 static inline void add_float (guint *, size_data *, ArgInfo *, gboolean);
427 static CallInfo * get_call_info (MonoMemPool *, MonoMethodSignature *);
428 static guchar * emit_float_to_int (MonoCompile *, guchar *, int, int, int, gboolean);
429 static __inline__ void emit_unwind_regs(MonoCompile *, guint8 *, int, int, long);
430 static void compare_and_branch(MonoBasicBlock *, MonoInst *, int, gboolean);
432 /*========================= End of Prototypes ======================*/
434 /*------------------------------------------------------------------*/
435 /* G l o b a l V a r i a b l e s */
436 /*------------------------------------------------------------------*/
438 __thread int indent_level = 0;
439 __thread FILE *trFd = NULL;
440 int curThreadNo = 0;
443 * The code generated for sequence points reads from this location,
444 * which is made read-only when single stepping is enabled.
446 static gpointer ss_trigger_page;
449 * Enabled breakpoints read from this trigger page
451 static gpointer bp_trigger_page;
453 breakpoint_t breakpointCode;
455 static mono_mutex_t mini_arch_mutex;
457 static const char * grNames[] = {
458 "s390_r0", "s390_sp", "s390_r2", "s390_r3", "s390_r4",
459 "s390_r5", "s390_r6", "s390_r7", "s390_r8", "s390_r9",
460 "s390_r10", "s390_r11", "s390_r12", "s390_r13", "s390_r14",
461 "s390_r15"
464 static const char * fpNames[] = {
465 "s390_f0", "s390_f1", "s390_f2", "s390_f3", "s390_f4",
466 "s390_f5", "s390_f6", "s390_f7", "s390_f8", "s390_f9",
467 "s390_f10", "s390_f11", "s390_f12", "s390_f13", "s390_f14",
468 "s390_f15"
471 static const char * vrNames[] = {
472 "vr0", "vr1", "vr2", "vr3", "vr4", "vr5", "vr6", "vr7",
473 "vr8", "vr9", "vr10", "vr11", "vr12", "vr13", "vr14", "vr15",
474 "vr16", "vr17", "vr18", "vr19", "vr20", "vr21", "vr22", "vr23",
475 "vr24", "vr25", "vr26", "vr27", "vr28", "vr29", "vr30", "vr31"
478 /*====================== End of Global Variables ===================*/
480 /*------------------------------------------------------------------*/
481 /* */
482 /* Name - mono_arch_regname */
483 /* */
484 /* Function - Returns the name of the register specified by */
485 /* the input parameter. */
486 /* */
487 /*------------------------------------------------------------------*/
489 const char*
490 mono_arch_regname (int reg)
492 if (reg >= 0 && reg < 16)
493 return grNames [reg];
494 else
495 return "unknown";
498 /*========================= End of Function ========================*/
500 /*------------------------------------------------------------------*/
501 /* */
502 /* Name - mono_arch_fregname */
503 /* */
504 /* Function - Returns the name of the register specified by */
505 /* the input parameter. */
506 /* */
507 /*------------------------------------------------------------------*/
509 const char*
510 mono_arch_fregname (int reg)
512 if (reg >= 0 && reg < 16)
513 return fpNames [reg];
514 else
515 return "unknown";
518 /*========================= End of Function ========================*/
520 /*------------------------------------------------------------------*/
521 /* */
522 /* Name - mono_arch_xregname */
523 /* */
524 /* Function - Returns the name of the register specified by */
525 /* the input parameter. */
526 /* */
527 /*------------------------------------------------------------------*/
529 const char *
530 mono_arch_xregname (int reg)
532 if (reg < s390_VR_NREG)
533 return vrNames [reg];
534 else
535 return "unknown";
538 /*========================= End of Function ========================*/
540 /*------------------------------------------------------------------*/
541 /* */
542 /* Name - arch_get_argument_info */
543 /* */
544 /* Function - Gathers information on parameters such as size, */
545 /* alignment, and padding. arg_info should be large */
546 /* enough to hold param_count + 1 entries. */
547 /* */
548 /* Parameters - @csig - Method signature */
549 /* @param_count - No. of parameters to consider */
550 /* @arg_info - An array to store the result info */
551 /* */
552 /* Returns - Size of the activation frame */
553 /* */
554 /*------------------------------------------------------------------*/
557 mono_arch_get_argument_info (MonoMethodSignature *csig,
558 int param_count,
559 MonoJitArgumentInfo *arg_info)
561 int k, frame_size = 0;
562 int size, align, pad;
563 int offset = 8;
565 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
566 frame_size += sizeof (target_mgreg_t);
567 offset += 8;
570 arg_info [0].offset = offset;
572 if (csig->hasthis) {
573 frame_size += sizeof (target_mgreg_t);
574 offset += 8;
577 arg_info [0].size = frame_size;
579 for (k = 0; k < param_count; k++) {
581 if (csig->pinvoke)
582 size = mono_type_native_stack_size (csig->params [k], (guint32 *) &align);
583 else
584 size = mini_type_stack_size (csig->params [k], &align);
586 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
587 arg_info [k].pad = pad;
588 frame_size += size;
589 arg_info [k + 1].pad = 0;
590 arg_info [k + 1].size = size;
591 offset += pad;
592 arg_info [k + 1].offset = offset;
593 offset += size;
596 align = MONO_ARCH_FRAME_ALIGNMENT;
597 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
598 arg_info [k].pad = pad;
600 return frame_size;
603 /*========================= End of Function ========================*/
605 /*------------------------------------------------------------------*/
606 /* */
607 /* Name - emit_unwind_regs. */
608 /* */
609 /* Function - Emit unwind information for a range of registers. */
610 /* */
611 /*------------------------------------------------------------------*/
613 static void __inline__
614 emit_unwind_regs(MonoCompile *cfg, guint8 *code, int start, int end, long offset)
616 int i;
618 for (i = start; i < end; i++) {
619 mono_emit_unwind_op_offset (cfg, code, i, offset);
620 mini_gc_set_slot_type_from_cfa (cfg, offset, SLOT_NOREF);
621 offset += sizeof(gulong);
625 /*========================= End of Function ========================*/
627 /*------------------------------------------------------------------*/
628 /* */
629 /* Name - retFitsInReg. */
630 /* */
631 /* Function - Determines if a value can be returned in one or */
632 /* two registers. */
633 /* */
634 /*------------------------------------------------------------------*/
636 static inline gboolean
637 retFitsInReg(guint32 size)
639 switch (size) {
640 case 0:
641 case 1:
642 case 2:
643 case 4:
644 case 8:
645 return (TRUE);
646 break;
647 default:
648 return (FALSE);
652 /*========================= End of Function ========================*/
654 /*------------------------------------------------------------------*/
655 /* */
656 /* Name - backStackPtr. */
657 /* */
658 /* Function - Restore Stack Pointer to previous frame. */
659 /* */
660 /*------------------------------------------------------------------*/
662 static inline guint8 *
663 backUpStackPtr(MonoCompile *cfg, guint8 *code)
665 int stackSize = cfg->stack_usage;
667 if (cfg->flags & MONO_CFG_HAS_ALLOCA) {
668 s390_lg (code, STK_BASE, 0, STK_BASE, 0);
669 } else {
670 if (cfg->frame_reg != STK_BASE)
671 s390_lgr (code, STK_BASE, cfg->frame_reg);
673 if (s390_is_imm16 (stackSize)) {
674 s390_aghi (code, STK_BASE, stackSize);
675 } else {
676 while (stackSize > 32767) {
677 s390_aghi (code, STK_BASE, 32767);
678 stackSize -= 32767;
680 s390_aghi (code, STK_BASE, stackSize);
684 return (code);
687 /*========================= End of Function ========================*/
689 /*------------------------------------------------------------------*/
690 /* */
691 /* Name - indent */
692 /* */
693 /* Function - Perform nice indenting to current level */
694 /* */
695 /*------------------------------------------------------------------*/
697 static void
698 indent (int diff) {
699 int v;
700 if (diff < 0)
701 indent_level += diff;
702 v = indent_level;
703 fprintf (trFd, "%p [%3d] ",(void *)pthread_self(),v);
704 while (v-- > 0) {
705 fprintf (trFd, ". ");
707 if (diff > 0)
708 indent_level += diff;
711 /*========================= End of Function ========================*/
713 /*------------------------------------------------------------------*/
714 /* */
715 /* Name - cvtMonoType */
716 /* */
717 /* Function - Convert a mono-type to a string. */
718 /* */
719 /*------------------------------------------------------------------*/
721 static const char *
722 cvtMonoType(MonoTypeEnum t)
724 switch(t)
726 case MONO_TYPE_END:
727 return "MONO_TYPE_END";
728 case MONO_TYPE_VOID:
729 return "MONO_TYPE_VOID";
730 case MONO_TYPE_BOOLEAN:
731 return "MONO_TYPE_BOOLEAN";
732 case MONO_TYPE_CHAR:
733 return "MONO_TYPE_CHAR";
734 case MONO_TYPE_I1:
735 return "MONO_TYPE_I1";
736 case MONO_TYPE_U1:
737 return "MONO_TYPE_U1";
738 case MONO_TYPE_I2:
739 return "MONO_TYPE_I2";
740 case MONO_TYPE_U2:
741 return "MONO_TYPE_U2";
742 case MONO_TYPE_I4:
743 return "MONO_TYPE_I4";
744 case MONO_TYPE_U4:
745 return "MONO_TYPE_U4";
746 case MONO_TYPE_I8:
747 return "MONO_TYPE_I8";
748 case MONO_TYPE_U8:
749 return "MONO_TYPE_U8";
750 case MONO_TYPE_R4:
751 return "MONO_TYPE_R4";
752 case MONO_TYPE_R8:
753 return "MONO_TYPE_R8";
754 case MONO_TYPE_STRING:
755 return "MONO_TYPE_STRING";
756 case MONO_TYPE_PTR:
757 return "MONO_TYPE_PTR";
758 case MONO_TYPE_BYREF:
759 return "MONO_TYPE_BYREF";
760 case MONO_TYPE_VALUETYPE:
761 return "MONO_TYPE_VALUETYPE";
762 case MONO_TYPE_CLASS:
763 return "MONO_TYPE_CLASS";
764 case MONO_TYPE_VAR:
765 return "MONO_TYPE_VAR";
766 case MONO_TYPE_ARRAY:
767 return "MONO_TYPE_ARRAY";
768 case MONO_TYPE_GENERICINST:
769 return "MONO_TYPE_GENERICINST";
770 case MONO_TYPE_TYPEDBYREF:
771 return "MONO_TYPE_TYPEDBYREF";
772 case MONO_TYPE_I:
773 return "MONO_TYPE_I";
774 case MONO_TYPE_U:
775 return "MONO_TYPE_U";
776 case MONO_TYPE_FNPTR:
777 return "MONO_TYPE_FNPTR";
778 case MONO_TYPE_OBJECT:
779 return "MONO_TYPE_OBJECT";
780 case MONO_TYPE_SZARRAY:
781 return "MONO_TYPE_SZARRAY";
782 case MONO_TYPE_MVAR:
783 return "MONO_TYPE_MVAR";
784 case MONO_TYPE_CMOD_REQD:
785 return "MONO_TYPE_CMOD_REQD";
786 case MONO_TYPE_CMOD_OPT:
787 return "MONO_TYPE_CMOD_OPT";
788 case MONO_TYPE_INTERNAL:
789 return "MONO_TYPE_INTERNAL";
790 case MONO_TYPE_MODIFIER:
791 return "MONO_TYPE_MODIFIER";
792 case MONO_TYPE_SENTINEL:
793 return "MONO_TYPE_SENTINEL";
794 case MONO_TYPE_PINNED:
795 return "MONO_TYPE_PINNED";
796 default:
799 return "unknown";
802 /*========================= End of Function ========================*/
804 /*------------------------------------------------------------------*/
805 /* */
806 /* Name - mono_arch_cpu_init */
807 /* */
808 /* Function - Perform CPU specific initialization to execute */
809 /* managed code. */
810 /* */
811 /*------------------------------------------------------------------*/
813 void
814 mono_arch_cpu_init (void)
818 /*========================= End of Function ========================*/
820 /*------------------------------------------------------------------*/
821 /* */
822 /* Name - mono_arch_init. */
823 /* */
824 /* Function - Initialize architecture specific code. */
825 /* */
826 /*------------------------------------------------------------------*/
828 void
829 mono_arch_init (void)
831 guint8 *code;
833 mono_set_partial_sharing_supported (FALSE);
834 mono_os_mutex_init_recursive (&mini_arch_mutex);
836 ss_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ, MONO_MEM_ACCOUNT_OTHER);
837 bp_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ, MONO_MEM_ACCOUNT_OTHER);
838 mono_mprotect (bp_trigger_page, mono_pagesize (), 0);
840 code = (guint8 *) &breakpointCode;
841 s390_basr(code, s390_r13, 0);
842 s390_j(code, 6);
843 s390_llong(code, 0);
844 s390_lg(code, s390_r13, 0, s390_r13, 4);
845 s390_lg(code, s390_r0, 0, s390_r13, 0);
848 /*========================= End of Function ========================*/
850 /*------------------------------------------------------------------*/
851 /* */
852 /* Name - mono_arch_cleanup. */
853 /* */
854 /* Function - Cleanup architecture specific code . */
855 /* */
856 /*------------------------------------------------------------------*/
858 void
859 mono_arch_cleanup (void)
861 if (ss_trigger_page)
862 mono_vfree (ss_trigger_page, mono_pagesize (), MONO_MEM_ACCOUNT_OTHER);
863 if (bp_trigger_page)
864 mono_vfree (bp_trigger_page, mono_pagesize (), MONO_MEM_ACCOUNT_OTHER);
865 mono_os_mutex_destroy (&mini_arch_mutex);
868 /*========================= End of Function ========================*/
870 /*------------------------------------------------------------------*/
871 /* */
872 /* Name - mono_arch_have_fast_tls */
873 /* */
874 /* Function - Returns whether we use fast inlined thread local */
875 /* storage managed access, instead of falling back */
876 /* to native code. */
877 /* */
878 /*------------------------------------------------------------------*/
880 gboolean
881 mono_arch_have_fast_tls (void)
883 return TRUE;
886 /*========================= End of Function ========================*/
888 /*------------------------------------------------------------------*/
889 /* */
890 /* Name - mono_arch_cpu_optimizations */
891 /* */
892 /* Function - Returns the optimizations supported on this CPU */
893 /* */
894 /*------------------------------------------------------------------*/
896 guint32
897 mono_arch_cpu_optimizations (guint32 *exclude_mask)
899 guint32 opts = 0;
901 /*----------------------------------------------------------*/
902 /* No s390-specific optimizations yet */
903 /*----------------------------------------------------------*/
904 *exclude_mask = MONO_OPT_LINEARS;
905 return opts;
908 /*========================= End of Function ========================*/
910 /*------------------------------------------------------------------*/
911 /* */
912 /* Name - mono_arch_get_allocatable_int_vars */
913 /* */
914 /* Function - */
915 /* */
916 /*------------------------------------------------------------------*/
918 GList *
919 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
921 GList *vars = NULL;
922 int i;
924 for (i = 0; i < cfg->num_varinfo; i++) {
925 MonoInst *ins = cfg->varinfo [i];
926 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
928 /* unused vars */
929 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
930 continue;
932 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) ||
933 (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
934 continue;
936 /* we can only allocate 32 bit values */
937 if (mono_is_regsize_var(ins->inst_vtype)) {
938 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
939 g_assert (i == vmv->idx);
940 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
944 return vars;
947 /*========================= End of Function ========================*/
949 /*------------------------------------------------------------------*/
950 /* */
951 /* Name - mono_arch_global_int_regs */
952 /* */
953 /* Function - Return a list of usable integer registers. */
954 /* */
955 /*------------------------------------------------------------------*/
957 GList *
958 mono_arch_get_global_int_regs (MonoCompile *cfg)
960 GList *regs = NULL;
961 MonoMethodHeader *header;
962 int i, top = 13;
964 header = cfg->header;
965 if ((cfg->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses)
966 cfg->frame_reg = s390_r11;
969 /* FIXME: s390_r12 is reserved for bkchain_reg. Only reserve it if needed */
970 top = 12;
971 for (i = 8; i < top; ++i) {
972 if ((cfg->frame_reg != i) &&
973 //!((cfg->uses_rgctx_reg) && (i == MONO_ARCH_IMT_REG)))
974 (i != MONO_ARCH_IMT_REG))
975 regs = g_list_prepend (regs, GUINT_TO_POINTER (i));
978 return regs;
981 /*========================= End of Function ========================*/
983 /*------------------------------------------------------------------*/
984 /* */
985 /* Name - mono_arch_flush_icache */
986 /* */
987 /* Function - Flush the CPU icache. */
988 /* */
989 /*------------------------------------------------------------------*/
991 void
992 mono_arch_flush_icache (guint8 *code, gint size)
996 /*========================= End of Function ========================*/
998 /*------------------------------------------------------------------*/
999 /* */
1000 /* Name - add_general */
1001 /* */
1002 /* Function - Determine code and stack size incremements for a */
1003 /* parameter. */
1004 /* */
1005 /*------------------------------------------------------------------*/
1007 static void inline
1008 add_general (guint *gr, size_data *sz, ArgInfo *ainfo)
1010 if (*gr > S390_LAST_ARG_REG) {
1011 sz->stack_size = S390_ALIGN(sz->stack_size, sizeof(long));
1012 ainfo->offset = sz->stack_size;
1013 ainfo->reg = STK_BASE;
1014 ainfo->regtype = RegTypeBase;
1015 sz->stack_size += sizeof(long);
1016 sz->local_size += sizeof(long);
1017 sz->offStruct += sizeof(long);
1018 sz->code_size += 12;
1019 } else {
1020 ainfo->reg = *gr;
1021 sz->code_size += 8;
1023 (*gr) ++;
1026 /*========================= End of Function ========================*/
1028 /*------------------------------------------------------------------*/
1029 /* */
1030 /* Name - add_stackParm */
1031 /* */
1032 /* Function - Determine code and stack size incremements for a */
1033 /* parameter. */
1034 /* */
1035 /*------------------------------------------------------------------*/
1037 static void inline
1038 add_stackParm (guint *gr, size_data *sz, ArgInfo *ainfo, gint size)
1040 if (*gr > S390_LAST_ARG_REG) {
1041 sz->stack_size = S390_ALIGN(sz->stack_size, sizeof(long));
1042 ainfo->reg = STK_BASE;
1043 ainfo->offset = sz->stack_size;
1044 ainfo->regtype = RegTypeStructByAddrOnStack;
1045 sz->stack_size += sizeof (target_mgreg_t);
1046 sz->parm_size += sizeof(gpointer);
1047 sz->offStruct += sizeof(gpointer);
1048 } else {
1049 ainfo->reg = *gr;
1050 ainfo->offset = sz->stack_size;
1051 ainfo->regtype = RegTypeStructByAddr;
1053 (*gr) ++;
1054 ainfo->offparm = sz->offset;
1055 sz->offset = S390_ALIGN(sz->offset+size, sizeof(long));
1056 ainfo->size = size;
1057 ainfo->vtsize = size;
1058 sz->parm_size += size;
1061 /*========================= End of Function ========================*/
1063 /*------------------------------------------------------------------*/
1064 /* */
1065 /* Name - add_float */
1066 /* */
1067 /* Function - Determine code and stack size incremements for a */
1068 /* float parameter. */
1069 /* */
1070 /*------------------------------------------------------------------*/
1072 static void inline
1073 add_float (guint *fr, size_data *sz, ArgInfo *ainfo, gboolean isDouble)
1075 if ((*fr) <= S390_LAST_FPARG_REG) {
1076 if (isDouble)
1077 ainfo->regtype = RegTypeFP;
1078 else
1079 ainfo->regtype = RegTypeFPR4;
1080 ainfo->reg = *fr;
1081 sz->code_size += 4;
1082 (*fr) += 2;
1084 else {
1085 ainfo->offset = sz->stack_size;
1086 ainfo->reg = STK_BASE;
1087 sz->code_size += 4;
1088 sz->stack_size += sizeof(double);
1089 sz->local_size += sizeof(double);
1090 sz->offStruct += sizeof(double);
1091 ainfo->regtype = RegTypeBase;
1095 /*========================= End of Function ========================*/
1097 /*------------------------------------------------------------------*/
1098 /* */
1099 /* Name - get_call_info */
1100 /* */
1101 /* Function - Determine the amount of space required for code */
1102 /* and stack. In addition determine starting points */
1103 /* for stack-based parameters, and area for struct- */
1104 /* ures being returned on the stack. */
1105 /* */
1106 /*------------------------------------------------------------------*/
1108 static CallInfo *
1109 get_call_info (MonoMemPool *mp, MonoMethodSignature *sig)
1111 guint i, fr, gr, size, pstart;
1112 int nParm = sig->hasthis + sig->param_count;
1113 MonoType *ret_type;
1114 guint32 simpleType, align;
1115 gboolean is_pinvoke = sig->pinvoke;
1116 CallInfo *cinfo;
1117 size_data *sz;
1119 if (mp)
1120 cinfo = mono_mempool_alloc0 (mp, sizeof (CallInfo) + sizeof (ArgInfo) * nParm);
1121 else
1122 cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * nParm);
1124 fr = 0;
1125 gr = s390_r2;
1126 nParm = 0;
1127 cinfo->struct_ret = 0;
1128 cinfo->sig = sig;
1129 sz = &cinfo->sz;
1130 sz->retStruct = 0;
1131 sz->offset = 0;
1132 sz->offStruct = S390_MINIMAL_STACK_SIZE;
1133 sz->stack_size = S390_MINIMAL_STACK_SIZE;
1134 sz->code_size = 0;
1135 sz->parm_size = 0;
1136 sz->local_size = 0;
1137 align = 0;
1138 size = 0;
1140 /*----------------------------------------------------------*/
1141 /* We determine the size of the return code/stack in case we*/
1142 /* need to reserve a register to be used to address a stack */
1143 /* area that the callee will use. */
1144 /*----------------------------------------------------------*/
1146 ret_type = mini_get_underlying_type (sig->ret);
1147 simpleType = ret_type->type;
1148 enum_retvalue:
1149 switch (simpleType) {
1150 case MONO_TYPE_I1:
1151 case MONO_TYPE_U1:
1152 case MONO_TYPE_I2:
1153 case MONO_TYPE_U2:
1154 case MONO_TYPE_I4:
1155 case MONO_TYPE_U4:
1156 case MONO_TYPE_I:
1157 case MONO_TYPE_U:
1158 case MONO_TYPE_OBJECT:
1159 case MONO_TYPE_PTR:
1160 case MONO_TYPE_FNPTR:
1161 cinfo->ret.reg = s390_r2;
1162 sz->code_size += 4;
1163 break;
1164 case MONO_TYPE_R4:
1165 case MONO_TYPE_R8:
1166 cinfo->ret.reg = s390_f0;
1167 sz->code_size += 4;
1168 break;
1169 case MONO_TYPE_I8:
1170 case MONO_TYPE_U8:
1171 cinfo->ret.reg = s390_r2;
1172 sz->code_size += 4;
1173 break;
1174 case MONO_TYPE_GENERICINST:
1175 if (!mono_type_generic_inst_is_valuetype (sig->ret)) {
1176 cinfo->ret.reg = s390_r2;
1177 sz->code_size += 4;
1178 break;
1180 /* Fall through */
1181 case MONO_TYPE_VALUETYPE: {
1182 MonoClass *klass = mono_class_from_mono_type_internal (sig->ret);
1183 if (m_class_is_enumtype (klass)) {
1184 simpleType = mono_class_enum_basetype_internal (klass)->type;
1185 goto enum_retvalue;
1187 size = mini_type_stack_size_full (m_class_get_byval_arg (klass), NULL, sig->pinvoke);
1189 cinfo->struct_ret = 1;
1190 cinfo->ret.size = size;
1191 cinfo->ret.vtsize = size;
1192 break;
1194 case MONO_TYPE_TYPEDBYREF:
1195 size = MONO_ABI_SIZEOF (MonoTypedRef);
1196 cinfo->struct_ret = 1;
1197 cinfo->ret.size = size;
1198 cinfo->ret.vtsize = size;
1199 break;
1200 case MONO_TYPE_VOID:
1201 break;
1202 default:
1203 g_error ("Can't handle as return value 0x%x", sig->ret->type);
1207 pstart = 0;
1209 * To simplify get_this_arg_reg () and LLVM integration, emit the vret arg after
1210 * the first argument, allowing 'this' to be always passed in the first arg reg.
1211 * Also do this if the first argument is a reference type, since virtual calls
1212 * are sometimes made using calli without sig->hasthis set, like in the delegate
1213 * invoke wrappers.
1215 if (cinfo->struct_ret && !is_pinvoke &&
1216 (sig->hasthis ||
1217 (sig->param_count > 0 &&
1218 MONO_TYPE_IS_REFERENCE (mini_get_underlying_type (sig->params [0]))))) {
1219 if (sig->hasthis) {
1220 cinfo->args[nParm].size = sizeof (target_mgreg_t);
1221 add_general (&gr, sz, cinfo->args + nParm);
1222 } else {
1223 cinfo->args[nParm].size = sizeof (target_mgreg_t);
1224 add_general (&gr, sz, &cinfo->args [sig->hasthis + nParm]);
1225 pstart = 1;
1227 nParm ++;
1228 cinfo->vret_arg_index = 1;
1229 cinfo->ret.reg = gr;
1230 gr ++;
1231 } else {
1232 /* this */
1233 if (sig->hasthis) {
1234 cinfo->args[nParm].size = sizeof (target_mgreg_t);
1235 add_general (&gr, sz, cinfo->args + nParm);
1236 nParm ++;
1239 if (cinfo->struct_ret) {
1240 cinfo->ret.reg = gr;
1241 gr ++;
1245 if ((sig->call_convention == MONO_CALL_VARARG) && (sig->param_count == 0)) {
1246 gr = S390_LAST_ARG_REG + 1;
1247 fr = S390_LAST_FPARG_REG + 1;
1249 /* Emit the signature cookie just before the implicit arguments */
1250 add_general (&gr, sz, &cinfo->sigCookie);
1253 /*----------------------------------------------------------*/
1254 /* We determine the size of the parameter code and stack */
1255 /* requirements by checking the types and sizes of the */
1256 /* parameters. */
1257 /*----------------------------------------------------------*/
1259 for (i = pstart; i < sig->param_count; ++i) {
1260 MonoType *ptype;
1262 /*--------------------------------------------------*/
1263 /* Handle vararg type calls. All args are put on */
1264 /* the stack. */
1265 /*--------------------------------------------------*/
1266 if ((sig->call_convention == MONO_CALL_VARARG) &&
1267 (i == sig->sentinelpos)) {
1268 gr = S390_LAST_ARG_REG + 1;
1269 fr = S390_LAST_FPARG_REG + 1;
1270 add_general (&gr, sz, &cinfo->sigCookie);
1273 if (sig->params [i]->byref) {
1274 add_general (&gr, sz, cinfo->args+nParm);
1275 cinfo->args[nParm].size = sizeof(gpointer);
1276 nParm++;
1277 continue;
1280 ptype = mini_get_underlying_type (sig->params [i]);
1281 simpleType = ptype->type;
1282 cinfo->args[nParm].type = simpleType;
1283 switch (simpleType) {
1284 case MONO_TYPE_I1:
1285 case MONO_TYPE_U1:
1286 cinfo->args[nParm].size = sizeof(char);
1287 add_general (&gr, sz, cinfo->args+nParm);
1288 nParm++;
1289 break;
1290 case MONO_TYPE_I2:
1291 case MONO_TYPE_U2:
1292 cinfo->args[nParm].size = sizeof(short);
1293 add_general (&gr, sz, cinfo->args+nParm);
1294 nParm++;
1295 break;
1296 case MONO_TYPE_I4:
1297 case MONO_TYPE_U4:
1298 cinfo->args[nParm].size = sizeof(int);
1299 add_general (&gr, sz, cinfo->args+nParm);
1300 nParm++;
1301 break;
1302 case MONO_TYPE_I:
1303 case MONO_TYPE_U:
1304 case MONO_TYPE_PTR:
1305 case MONO_TYPE_FNPTR:
1306 case MONO_TYPE_OBJECT:
1307 cinfo->args[nParm].size = sizeof(gpointer);
1308 add_general (&gr, sz, cinfo->args+nParm);
1309 nParm++;
1310 break;
1311 case MONO_TYPE_I8:
1312 case MONO_TYPE_U8:
1313 cinfo->args[nParm].size = sizeof(long long);
1314 add_general (&gr, sz, cinfo->args+nParm);
1315 nParm++;
1316 break;
1317 case MONO_TYPE_R4:
1318 cinfo->args[nParm].size = sizeof(float);
1319 add_float (&fr, sz, cinfo->args+nParm, FALSE);
1320 nParm++;
1321 break;
1322 case MONO_TYPE_R8:
1323 cinfo->args[nParm].size = sizeof(double);
1324 add_float (&fr, sz, cinfo->args+nParm, TRUE);
1325 nParm++;
1326 break;
1327 case MONO_TYPE_GENERICINST:
1328 if (!mono_type_generic_inst_is_valuetype (ptype)) {
1329 cinfo->args[nParm].size = sizeof(gpointer);
1330 add_general (&gr, sz, cinfo->args+nParm);
1331 nParm++;
1332 break;
1334 /* Fall through */
1335 case MONO_TYPE_VALUETYPE: {
1336 MonoMarshalType *info;
1337 MonoClass *klass = mono_class_from_mono_type_internal (ptype);
1339 if (sig->pinvoke)
1340 size = mono_class_native_size(klass, NULL);
1341 else
1342 size = mono_class_value_size(klass, NULL);
1344 if (simpleType != MONO_TYPE_GENERICINST) {
1345 info = mono_marshal_load_type_info(klass);
1347 if ((info->native_size == sizeof(float)) &&
1348 (info->num_fields == 1) &&
1349 (info->fields[0].field->type->type == MONO_TYPE_R4)) {
1350 cinfo->args[nParm].size = sizeof(float);
1351 add_float(&fr, sz, cinfo->args+nParm, FALSE);
1352 nParm ++;
1353 break;
1356 if ((info->native_size == sizeof(double)) &&
1357 (info->num_fields == 1) &&
1358 (info->fields[0].field->type->type == MONO_TYPE_R8)) {
1359 cinfo->args[nParm].size = sizeof(double);
1360 add_float(&fr, sz, cinfo->args+nParm, TRUE);
1361 nParm ++;
1362 break;
1366 cinfo->args[nParm].vtsize = 0;
1367 cinfo->args[nParm].size = 0;
1369 switch (size) {
1370 /*----------------------------------*/
1371 /* On S/390, structures of size 1, */
1372 /* 2, 4, and 8 bytes are passed in */
1373 /* (a) register(s). */
1374 /*----------------------------------*/
1375 case 0:
1376 case 1:
1377 case 2:
1378 case 4:
1379 case 8:
1380 add_general(&gr, sz, cinfo->args+nParm);
1381 cinfo->args[nParm].size = size;
1382 cinfo->args[nParm].regtype = RegTypeStructByVal;
1383 nParm++;
1384 sz->local_size += sizeof(long);
1385 break;
1386 default:
1387 add_stackParm(&gr, sz, cinfo->args+nParm, size);
1388 nParm++;
1391 break;
1392 case MONO_TYPE_TYPEDBYREF: {
1393 int size = MONO_ABI_SIZEOF (MonoTypedRef);
1395 cinfo->args[nParm].vtsize = 0;
1396 cinfo->args[nParm].size = 0;
1398 switch (size) {
1399 /*----------------------------------*/
1400 /* On S/390, structures of size 1, */
1401 /* 2, 4, and 8 bytes are passed in */
1402 /* (a) register(s). */
1403 /*----------------------------------*/
1404 case 0:
1405 case 1:
1406 case 2:
1407 case 4:
1408 case 8:
1409 add_general(&gr, sz, cinfo->args+nParm);
1410 cinfo->args[nParm].size = size;
1411 cinfo->args[nParm].regtype = RegTypeStructByVal;
1412 nParm++;
1413 sz->local_size += sizeof(long);
1414 break;
1415 default:
1416 add_stackParm(&gr, sz, cinfo->args+nParm, size);
1417 nParm++;
1420 break;
1421 default:
1422 g_error ("Can't trampoline 0x%x", ptype);
1426 /*----------------------------------------------------------*/
1427 /* Handle the case where there are no implicit arguments */
1428 /*----------------------------------------------------------*/
1429 if ((sig->call_convention == MONO_CALL_VARARG) &&
1430 (nParm > 0) &&
1431 (!sig->pinvoke) &&
1432 (sig->param_count == sig->sentinelpos)) {
1433 gr = S390_LAST_ARG_REG + 1;
1434 fr = S390_LAST_FPARG_REG + 1;
1435 add_general (&gr, sz, &cinfo->sigCookie);
1438 /*----------------------------------------------------------*/
1439 /* If we are passing a structure back then if it won't be */
1440 /* in a register(s) then we make room at the end of the */
1441 /* parameters that may have been placed on the stack */
1442 /*----------------------------------------------------------*/
1443 if (cinfo->struct_ret) {
1444 cinfo->ret.offset = sz->stack_size;
1445 switch (cinfo->ret.size) {
1446 case 0:
1447 case 1:
1448 case 2:
1449 case 4:
1450 case 8:
1451 break;
1452 default:
1453 sz->stack_size += S390_ALIGN(cinfo->ret.size, align);
1457 cinfo->lastgr = gr;
1458 sz->stack_size = sz->stack_size + sz->local_size + sz->parm_size +
1459 sz->offset;
1460 sz->stack_size = S390_ALIGN(sz->stack_size, sizeof(long));
1462 return (cinfo);
1465 /*========================= End of Function ========================*/
1467 /*------------------------------------------------------------------*/
1468 /* */
1469 /* Name - mono_arch_allocate_vars */
1470 /* */
1471 /* Function - Set var information according to the calling */
1472 /* convention for S/390. The local var stuff should */
1473 /* most likely be split in another method. */
1474 /* */
1475 /* Parameter - @m - Compile unit. */
1476 /* */
1477 /*------------------------------------------------------------------*/
1479 void
1480 mono_arch_allocate_vars (MonoCompile *cfg)
1482 MonoMethodSignature *sig;
1483 MonoMethodHeader *header;
1484 MonoInst *inst;
1485 CallInfo *cinfo;
1486 int iParm, iVar, offset, align, size, curinst;
1487 int frame_reg = STK_BASE;
1488 int sArg, eArg;
1490 header = cfg->header;
1492 cfg->flags |= MONO_CFG_HAS_SPILLUP;
1494 /*---------------------------------------------------------*/
1495 /* We use the frame register also for any method that has */
1496 /* filter clauses. This way, when the handlers are called, */
1497 /* the code will reference local variables using the frame */
1498 /* reg instead of the stack pointer: if we had to restore */
1499 /* the stack pointer, we'd corrupt the method frames that */
1500 /* are already on the stack (since filters get called */
1501 /* before stack unwinding happens) when the filter code */
1502 /* would call any method. */
1503 /*---------------------------------------------------------*/
1504 if ((cfg->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses)
1505 frame_reg = s390_r11;
1507 cfg->frame_reg = frame_reg;
1509 cfg->arch.bkchain_reg = -1;
1511 if (frame_reg != STK_BASE)
1512 cfg->used_int_regs |= (1LL << frame_reg);
1514 sig = mono_method_signature_internal (cfg->method);
1516 cinfo = get_call_info (cfg->mempool, sig);
1518 if (!cinfo->struct_ret) {
1519 switch (mini_get_underlying_type (sig->ret)->type) {
1520 case MONO_TYPE_VOID:
1521 break;
1522 default:
1523 cfg->ret->opcode = OP_REGVAR;
1524 cfg->ret->dreg = s390_r2;
1525 break;
1529 /*--------------------------------------------------------------*/
1530 /* local vars are at a positive offset from the stack pointer */
1531 /* also note that if the function uses alloca, we use s390_r11 */
1532 /* to point at the local variables. */
1533 /* add parameter area size for called functions */
1534 /*--------------------------------------------------------------*/
1535 if (cfg->param_area == 0)
1536 offset = S390_MINIMAL_STACK_SIZE;
1537 else
1538 offset = cfg->param_area;
1540 cfg->sig_cookie = 0;
1542 if (cinfo->struct_ret) {
1543 inst = cfg->vret_addr;
1544 offset = S390_ALIGN(offset, sizeof(gpointer));
1545 inst->inst_offset = offset;
1546 inst->opcode = OP_REGOFFSET;
1547 inst->inst_basereg = frame_reg;
1548 offset += sizeof(gpointer);
1549 if (G_UNLIKELY (cfg->verbose_level > 1)) {
1550 printf ("vret_addr =");
1551 mono_print_ins (cfg->vret_addr);
1555 if (sig->hasthis) {
1556 inst = cfg->args [0];
1557 if (inst->opcode != OP_REGVAR) {
1558 inst->opcode = OP_REGOFFSET;
1559 inst->inst_basereg = frame_reg;
1560 offset = S390_ALIGN(offset, sizeof(gpointer));
1561 inst->inst_offset = offset;
1562 offset += sizeof (target_mgreg_t);
1564 curinst = sArg = 1;
1565 } else {
1566 curinst = sArg = 0;
1569 eArg = sig->param_count + sArg;
1571 if (sig->call_convention == MONO_CALL_VARARG)
1572 cfg->sig_cookie += S390_MINIMAL_STACK_SIZE;
1574 for (iParm = sArg; iParm < eArg; ++iParm) {
1575 inst = cfg->args [curinst];
1576 if (inst->opcode != OP_REGVAR) {
1577 switch (cinfo->args[iParm].regtype) {
1578 case RegTypeStructByAddr : {
1579 MonoInst *indir;
1581 size = sizeof (target_mgreg_t);
1583 inst->opcode = OP_REGOFFSET;
1584 inst->inst_basereg = frame_reg;
1585 offset = S390_ALIGN (offset, sizeof (target_mgreg_t));
1586 inst->inst_offset = offset;
1588 /* Add a level of indirection */
1589 MONO_INST_NEW (cfg, indir, 0);
1590 *indir = *inst;
1591 inst->opcode = OP_VTARG_ADDR;
1592 inst->inst_left = indir;
1594 break;
1595 case RegTypeStructByAddrOnStack : {
1596 MonoInst *indir;
1598 size = sizeof (target_mgreg_t);
1600 /* Similar to the == STK_BASE case below */
1601 cfg->arch.bkchain_reg = s390_r12;
1602 cfg->used_int_regs |= 1 << cfg->arch.bkchain_reg;
1604 inst->opcode = OP_REGOFFSET;
1605 inst->dreg = mono_alloc_preg (cfg);
1606 inst->inst_basereg = cfg->arch.bkchain_reg;
1607 inst->inst_offset = cinfo->args [iParm].offset;
1609 /* Add a level of indirection */
1610 MONO_INST_NEW (cfg, indir, 0);
1611 *indir = *inst;
1612 inst->opcode = OP_VTARG_ADDR;
1613 inst->inst_left = indir;
1614 break;
1616 case RegTypeStructByVal :
1617 size = cinfo->args[iParm].size;
1618 offset = S390_ALIGN(offset, size);
1619 inst->opcode = OP_REGOFFSET;
1620 inst->inst_basereg = frame_reg;
1621 inst->inst_offset = offset;
1622 break;
1623 default :
1624 if (cinfo->args [iParm].reg == STK_BASE) {
1626 * These arguments are in the previous frame, so we can't
1627 * compute their offset from the current frame pointer right
1628 * now, since cfg->stack_offset is not yet known, so dedicate a
1629 * register holding the previous frame pointer.
1631 cfg->arch.bkchain_reg = s390_r12;
1632 cfg->used_int_regs |= 1 << cfg->arch.bkchain_reg;
1634 inst->opcode = OP_REGOFFSET;
1635 inst->inst_basereg = cfg->arch.bkchain_reg;
1636 size = (cinfo->args[iParm].size < 8
1637 ? 8 - cinfo->args[iParm].size
1638 : 0);
1639 inst->inst_offset = cinfo->args [iParm].offset + size;
1640 size = sizeof (long);
1641 } else {
1642 inst->opcode = OP_REGOFFSET;
1643 inst->inst_basereg = frame_reg;
1644 size = (cinfo->args[iParm].size < 8
1645 ? sizeof(int)
1646 : sizeof(long));
1647 offset = S390_ALIGN(offset, size);
1648 if (cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1649 inst->inst_offset = offset;
1650 else
1651 inst->inst_offset = offset + (8 - size);
1653 break;
1655 offset += MAX(size, 8);
1657 curinst++;
1660 cfg->locals_min_stack_offset = offset;
1662 curinst = cfg->locals_start;
1663 for (iVar = curinst; iVar < cfg->num_varinfo; ++iVar) {
1664 inst = cfg->varinfo [iVar];
1665 if ((inst->flags & MONO_INST_IS_DEAD) ||
1666 (inst->opcode == OP_REGVAR))
1667 continue;
1669 /*--------------------------------------------------*/
1670 /* inst->backend.is_pinvoke indicates native sized */
1671 /* value types this is used by the pinvoke wrappers */
1672 /* when they call functions returning structure */
1673 /*--------------------------------------------------*/
1674 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype))
1675 size = mono_class_native_size (mono_class_from_mono_type_internal (inst->inst_vtype),
1676 (guint32 *) &align);
1677 else
1678 size = mono_type_size (inst->inst_vtype, &align);
1680 offset = S390_ALIGN(offset, align);
1681 inst->inst_offset = offset;
1682 inst->opcode = OP_REGOFFSET;
1683 inst->inst_basereg = frame_reg;
1684 offset += size;
1685 DEBUG (g_print("allocating local %d to %ld, size: %d\n",
1686 iVar, inst->inst_offset, size));
1689 cfg->locals_max_stack_offset = offset;
1691 /*------------------------------------------------------*/
1692 /* Reserve space to save LMF and caller saved registers */
1693 /*------------------------------------------------------*/
1694 if (cfg->method->save_lmf)
1695 offset += sizeof (MonoLMF);
1697 /*------------------------------------------------------*/
1698 /* align the offset */
1699 /*------------------------------------------------------*/
1700 cfg->stack_offset = S390_ALIGN(offset, S390_STACK_ALIGNMENT);
1702 /*------------------------------------------------------*/
1703 /* Fix offsets for args whose value is in parent frame */
1704 /*------------------------------------------------------*/
1705 for (iParm = sArg; iParm < eArg; ++iParm) {
1706 inst = cfg->args [iParm];
1708 if (inst->opcode == OP_S390_STKARG) {
1709 inst->opcode = OP_REGOFFSET;
1710 inst->inst_offset += cfg->stack_offset;
1715 /*========================= End of Function ========================*/
1717 /*------------------------------------------------------------------*/
1718 /* */
1719 /* Name - mono_arch_create_vars */
1720 /* */
1721 /*------------------------------------------------------------------*/
1723 void
1724 mono_arch_create_vars (MonoCompile *cfg)
1726 MonoMethodSignature *sig;
1727 CallInfo *cinfo;
1729 sig = mono_method_signature_internal (cfg->method);
1731 cinfo = get_call_info (cfg->mempool, sig);
1733 if (cinfo->struct_ret) {
1734 cfg->vret_addr = mono_compile_create_var (cfg, mono_get_int_type (), OP_ARG);
1735 if (G_UNLIKELY (cfg->verbose_level > 1)) {
1736 printf ("vret_addr = ");
1737 mono_print_ins (cfg->vret_addr);
1742 /*========================= End of Function ========================*/
1744 /*------------------------------------------------------------------*/
1745 /* */
1746 /* Name - add_outarg_reg2. */
1747 /* */
1748 /*------------------------------------------------------------------*/
1750 static void
1751 add_outarg_reg2 (MonoCompile *cfg, MonoCallInst *call, ArgStorage storage, int reg, MonoInst *tree)
1753 MonoInst *ins;
1755 switch (storage) {
1756 case RegTypeGeneral:
1757 MONO_INST_NEW (cfg, ins, OP_MOVE);
1758 ins->dreg = mono_alloc_ireg (cfg);
1759 ins->sreg1 = tree->dreg;
1760 MONO_ADD_INS (cfg->cbb, ins);
1761 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, reg, FALSE);
1762 break;
1763 case RegTypeFP:
1764 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1765 ins->dreg = mono_alloc_freg (cfg);
1766 ins->sreg1 = tree->dreg;
1767 MONO_ADD_INS (cfg->cbb, ins);
1768 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, reg, TRUE);
1769 break;
1770 case RegTypeFPR4:
1771 MONO_INST_NEW (cfg, ins, OP_S390_SETF4RET);
1772 ins->dreg = mono_alloc_freg (cfg);
1773 ins->sreg1 = tree->dreg;
1774 MONO_ADD_INS (cfg->cbb, ins);
1775 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, reg, TRUE);
1776 break;
1777 default:
1778 g_assert_not_reached ();
1782 /*========================= End of Function ========================*/
1784 /*------------------------------------------------------------------*/
1785 /* */
1786 /* Name - emit_sig_cookie. */
1787 /* */
1788 /*------------------------------------------------------------------*/
1790 static void
1791 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1793 MonoMethodSignature *tmpSig;
1794 MonoInst *sig_arg;
1796 cfg->disable_aot = TRUE;
1798 /*----------------------------------------------------------*/
1799 /* mono_ArgIterator_Setup assumes the signature cookie is */
1800 /* passed first and all the arguments which were before it */
1801 /* passed on the stack after the signature. So compensate */
1802 /* by passing a different signature. */
1803 /*----------------------------------------------------------*/
1804 tmpSig = mono_metadata_signature_dup (call->signature);
1805 tmpSig->param_count -= call->signature->sentinelpos;
1806 tmpSig->sentinelpos = 0;
1807 if (tmpSig->param_count > 0)
1808 memcpy (tmpSig->params,
1809 call->signature->params + call->signature->sentinelpos,
1810 tmpSig->param_count * sizeof(MonoType *));
1812 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
1813 sig_arg->dreg = mono_alloc_ireg (cfg);
1814 sig_arg->inst_p0 = tmpSig;
1815 MONO_ADD_INS (cfg->cbb, sig_arg);
1817 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, STK_BASE,
1818 cinfo->sigCookie.offset, sig_arg->dreg);
1821 /*========================= End of Function ========================*/
1823 /*------------------------------------------------------------------*/
1824 /* */
1825 /* Name - mono_arch_emit_call */
1826 /* */
1827 /*------------------------------------------------------------------*/
1829 void
1830 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1832 MonoInst *in;
1833 MonoMethodSignature *sig;
1834 MonoInst *ins;
1835 int i, n, lParamArea;
1836 CallInfo *cinfo;
1837 ArgInfo *ainfo = NULL;
1838 int stackSize;
1839 MonoMethodHeader *header;
1841 sig = call->signature;
1842 n = sig->param_count + sig->hasthis;
1843 DEBUG (g_print ("Call requires: %d parameters\n",n));
1845 cinfo = get_call_info (cfg->mempool, sig);
1847 stackSize = cinfo->sz.stack_size + cinfo->sz.local_size +
1848 cinfo->sz.parm_size + cinfo->sz.offset;
1849 call->stack_usage = MAX(stackSize, call->stack_usage);
1850 lParamArea = MAX((call->stack_usage-S390_MINIMAL_STACK_SIZE-cinfo->sz.parm_size), 0);
1851 cfg->param_area = MAX(((signed) cfg->param_area), lParamArea);
1852 cfg->flags |= MONO_CFG_HAS_CALLS;
1854 if (cinfo->struct_ret) {
1855 MONO_INST_NEW (cfg, ins, OP_MOVE);
1856 ins->sreg1 = call->vret_var->dreg;
1857 ins->dreg = mono_alloc_preg (cfg);
1858 MONO_ADD_INS (cfg->cbb, ins);
1859 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, cinfo->ret.reg, FALSE);
1862 header = cfg->header;
1864 for (i = 0; i < n; ++i) {
1865 MonoType *t;
1867 ainfo = cinfo->args + i;
1868 if (i >= sig->hasthis)
1869 t = sig->params [i - sig->hasthis];
1870 else
1871 t = mono_get_int_type ();
1872 t = mini_get_underlying_type (t);
1874 in = call->args [i];
1876 if ((sig->call_convention == MONO_CALL_VARARG) &&
1877 (!sig->pinvoke) &&
1878 (i == sig->sentinelpos)) {
1879 emit_sig_cookie (cfg, call, cinfo);
1882 switch (ainfo->regtype) {
1883 case RegTypeGeneral :
1884 add_outarg_reg2 (cfg, call, ainfo->regtype, ainfo->reg, in);
1885 break;
1886 case RegTypeFP :
1887 case RegTypeFPR4 :
1888 if (MONO_TYPE_ISSTRUCT (t)) {
1889 /* Valuetype passed in one fp register */
1890 ainfo->regtype = RegTypeStructByValInFP;
1891 /* Fall through */
1892 } else {
1893 add_outarg_reg2 (cfg, call, ainfo->regtype, ainfo->reg, in);
1894 break;
1896 case RegTypeStructByVal :
1897 case RegTypeStructByAddr :
1898 case RegTypeStructByAddrOnStack : {
1899 guint32 align;
1900 guint32 size;
1902 if (sig->params [i - sig->hasthis]->type == MONO_TYPE_TYPEDBYREF) {
1903 size = MONO_ABI_SIZEOF (MonoTypedRef);
1904 align = sizeof (target_mgreg_t);
1906 else
1907 if (sig->pinvoke)
1908 size = mono_type_native_stack_size (m_class_get_byval_arg (in->klass), &align);
1909 else {
1911 * Other backends use mono_type_stack_size (), but that
1912 * aligns the size to 8, which is larger than the size of
1913 * the source, leading to reads of invalid memory if the
1914 * source is at the end of address space.
1916 size = mono_class_value_size (in->klass, &align);
1919 g_assert (in->klass);
1921 ainfo->offparm += cinfo->sz.offStruct;
1923 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1924 ins->sreg1 = in->dreg;
1925 ins->klass = in->klass;
1926 ins->backend.size = ainfo->size;
1927 ins->inst_p0 = call;
1928 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1929 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1931 MONO_ADD_INS (cfg->cbb, ins);
1933 break;
1935 case RegTypeBase :
1936 if (!t->byref && t->type == MONO_TYPE_R4) {
1937 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG,
1938 STK_BASE, ainfo->offset + 4,
1939 in->dreg);
1940 } else if (!t->byref && (t->type == MONO_TYPE_R8)) {
1941 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG,
1942 STK_BASE, ainfo->offset,
1943 in->dreg);
1944 } else {
1945 MONO_INST_NEW (cfg, ins, OP_STORE_MEMBASE_REG);
1946 ins->inst_destbasereg = STK_BASE;
1947 ins->inst_offset = ainfo->offset;
1948 ins->sreg1 = in->dreg;
1949 MONO_ADD_INS (cfg->cbb, ins);
1951 break;
1952 default:
1953 g_assert_not_reached ();
1954 break;
1959 * Handle the case where there are no implicit arguments
1961 if ((sig->call_convention == MONO_CALL_VARARG) &&
1962 (!sig->pinvoke) &&
1963 (i == sig->sentinelpos)) {
1964 emit_sig_cookie (cfg, call, cinfo);
1967 if (cinfo->struct_ret) {
1968 MonoInst *vtarg;
1970 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1971 vtarg->sreg1 = call->vret_var->dreg;
1972 vtarg->dreg = mono_alloc_preg (cfg);
1973 MONO_ADD_INS (cfg->cbb, vtarg);
1975 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1979 /*========================= End of Function ========================*/
1981 /*------------------------------------------------------------------*/
1982 /* */
1983 /* Name - mono_arch_emit_outarg_vt */
1984 /* */
1985 /*------------------------------------------------------------------*/
1987 void
1988 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1990 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1991 ArgInfo *ainfo = (ArgInfo*)ins->inst_p1;
1992 int size = ins->backend.size;
1994 if (ainfo->regtype == RegTypeStructByVal) {
1996 arg->ins.sreg1 = ainfo->reg;
1997 arg->ins.opcode = OP_OUTARG_VT;
1998 arg->size = ainfo->size;
1999 arg->offset = ainfo->offset;
2000 arg->offPrm = ainfo->offparm + cinfo->sz.offStruct;
2002 if (ainfo->reg != STK_BASE) {
2003 MONO_OUTPUT_VTR (cfg, size, ainfo->reg, src->dreg, 0);
2004 } else {
2005 MONO_OUTPUT_VTS (cfg, size, ainfo->reg, ainfo->offset,
2006 src->dreg, 0);
2008 } else if (ainfo->regtype == RegTypeStructByValInFP) {
2009 int dreg = mono_alloc_freg (cfg);
2011 if (ainfo->size == 4) {
2012 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, dreg, src->dreg, 0);
2013 MONO_EMIT_NEW_UNALU (cfg, OP_S390_SETF4RET, dreg, dreg);
2014 } else {
2015 g_assert (ainfo->size == 8);
2017 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, dreg, src->dreg, 0);
2020 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
2021 } else {
2022 ERROR_DECL (error);
2023 MonoMethodHeader *header;
2024 MonoInst *vtcopy = mono_compile_create_var (cfg, m_class_get_byval_arg (src->klass), OP_LOCAL);
2025 MonoInst *load;
2026 int ovf_size = ainfo->vtsize,
2027 srcReg;
2028 guint32 size;
2030 /* FIXME: alignment? */
2031 if (call->signature->pinvoke) {
2032 size = mono_type_native_stack_size (m_class_get_byval_arg (src->klass), NULL);
2033 vtcopy->backend.is_pinvoke = 1;
2034 } else {
2035 size = mini_type_stack_size (m_class_get_byval_arg (src->klass), NULL);
2037 if (size > 0)
2038 g_assert (ovf_size > 0);
2040 header = mono_method_get_header_checked (cfg->method, error);
2041 mono_error_assert_ok (error); /* FIXME don't swallow the error */
2042 if ((cfg->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses)
2043 srcReg = s390_r11;
2044 else
2045 srcReg = STK_BASE;
2047 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
2048 mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, size, TARGET_SIZEOF_VOID_P);
2050 if (ainfo->reg == STK_BASE) {
2051 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, srcReg, ainfo->offset, load->dreg);
2053 if (cfg->compute_gc_maps) {
2054 MonoInst *def;
2056 EMIT_NEW_GC_PARAM_SLOT_LIVENESS_DEF (cfg, def, ainfo->offset, m_class_get_byval_arg (ins->klass));
2058 } else
2059 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
2063 /*========================= End of Function ========================*/
2065 /*------------------------------------------------------------------*/
2066 /* */
2067 /* Name - mono_arch_emit_setret */
2068 /* */
2069 /*------------------------------------------------------------------*/
2071 void
2072 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
2074 MonoType *ret = mini_get_underlying_type (mono_method_signature_internal (method)->ret);
2076 if (!ret->byref) {
2077 if (ret->type == MONO_TYPE_R4) {
2078 MONO_EMIT_NEW_UNALU (cfg, OP_S390_SETF4RET, s390_f0, val->dreg);
2079 return;
2080 } else if (ret->type == MONO_TYPE_R8) {
2081 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, s390_f0, val->dreg);
2082 return;
2086 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
2089 /*========================= End of Function ========================*/
2091 /*------------------------------------------------------------------*/
2092 /* */
2093 /* Name - compare_and_branch */
2094 /* */
2095 /* Function - Form a peephole pass at the code looking for */
2096 /* simple optimizations. */
2097 /* */
2098 /*------------------------------------------------------------------*/
2100 static void
2101 compare_and_branch(MonoBasicBlock *bb, MonoInst *ins, int cc, gboolean logical)
2103 MonoInst *last;
2105 if (mono_hwcap_s390x_has_gie) {
2106 last = mono_inst_prev (ins, FILTER_IL_SEQ_POINT);
2107 ins->sreg1 = last->sreg1;
2108 ins->sreg2 = last->sreg2;
2109 ins->sreg3 = cc;
2110 switch(last->opcode) {
2111 case OP_ICOMPARE:
2112 if (logical)
2113 ins->opcode = OP_S390_CLRJ;
2114 else
2115 ins->opcode = OP_S390_CRJ;
2116 MONO_DELETE_INS(bb, last);
2117 break;
2118 case OP_COMPARE:
2119 case OP_LCOMPARE:
2120 if (logical)
2121 ins->opcode = OP_S390_CLGRJ;
2122 else
2123 ins->opcode = OP_S390_CGRJ;
2124 MONO_DELETE_INS(bb, last);
2125 break;
2126 case OP_ICOMPARE_IMM:
2127 ins->backend.data = (gpointer) last->inst_imm;
2128 if (logical)
2129 ins->opcode = OP_S390_CLIJ;
2130 else
2131 ins->opcode = OP_S390_CIJ;
2132 MONO_DELETE_INS(bb, last);
2133 break;
2134 case OP_COMPARE_IMM:
2135 case OP_LCOMPARE_IMM:
2136 ins->backend.data = (gpointer) last->inst_imm;
2137 if (logical)
2138 ins->opcode = OP_S390_CLGIJ;
2139 else
2140 ins->opcode = OP_S390_CGIJ;
2141 MONO_DELETE_INS(bb, last);
2142 break;
2147 /*========================= End of Function ========================*/
2149 /*------------------------------------------------------------------*/
2150 /* */
2151 /* Name - mono_arch_peephole_pass_1 */
2152 /* */
2153 /* Function - Form a peephole pass at the code looking for */
2154 /* simple optimizations. */
2155 /* */
2156 /*------------------------------------------------------------------*/
2158 void
2159 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
2161 MonoInst *ins, *n;
2163 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
2164 switch (ins->opcode) {
2165 case OP_IBEQ:
2166 case OP_LBEQ:
2167 compare_and_branch(bb, ins, S390_CC_EQ, FALSE);
2168 break;
2169 case OP_LBNE_UN:
2170 case OP_IBNE_UN:
2171 compare_and_branch(bb, ins, S390_CC_NE, TRUE);
2172 break;
2173 case OP_LBLT:
2174 case OP_IBLT:
2175 compare_and_branch(bb, ins, S390_CC_LT, FALSE);
2176 break;
2177 case OP_LBLT_UN:
2178 case OP_IBLT_UN:
2179 compare_and_branch(bb, ins, S390_CC_LT, TRUE);
2180 break;
2181 case OP_LBGT:
2182 case OP_IBGT:
2183 compare_and_branch(bb, ins, S390_CC_GT, FALSE);
2184 break;
2185 case OP_LBGT_UN:
2186 case OP_IBGT_UN:
2187 compare_and_branch(bb, ins, S390_CC_GT, TRUE);
2188 break;
2189 case OP_LBGE:
2190 case OP_IBGE:
2191 compare_and_branch(bb, ins, S390_CC_GE, FALSE);
2192 break;
2193 case OP_LBGE_UN:
2194 case OP_IBGE_UN:
2195 compare_and_branch(bb, ins, S390_CC_GE, TRUE);
2196 break;
2197 case OP_LBLE:
2198 case OP_IBLE:
2199 compare_and_branch(bb, ins, S390_CC_LE, FALSE);
2200 break;
2201 case OP_LBLE_UN:
2202 case OP_IBLE_UN:
2203 compare_and_branch(bb, ins, S390_CC_LE, TRUE);
2204 break;
2206 // default:
2207 // mono_peephole_ins (bb, ins);
2212 /*========================= End of Function ========================*/
2214 /*------------------------------------------------------------------*/
2215 /* */
2216 /* Name - mono_arch_peephole_pass_2 */
2217 /* */
2218 /* Function - Form a peephole pass at the code looking for */
2219 /* simple optimizations. */
2220 /* */
2221 /*------------------------------------------------------------------*/
2223 void
2224 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
2226 MonoInst *ins, *n, *last_ins = NULL;
2228 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
2229 switch (ins->opcode) {
2230 case OP_LOADU4_MEMBASE:
2231 case OP_LOADI4_MEMBASE:
2232 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG) &&
2233 ins->inst_basereg == last_ins->inst_destbasereg &&
2234 ins->inst_offset == last_ins->inst_offset) {
2235 ins->opcode = (ins->opcode == OP_LOADI4_MEMBASE) ? OP_ICONV_TO_I4 : OP_ICONV_TO_U4;
2236 ins->sreg1 = last_ins->sreg1;
2238 break;
2240 mono_peephole_ins (bb, ins);
2244 /*========================= End of Function ========================*/
2246 /*------------------------------------------------------------------*/
2247 /* */
2248 /* Name - mono_arch_lowering_pass. */
2249 /* */
2250 /*------------------------------------------------------------------*/
2252 void
2253 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2255 MonoInst *ins, *next;
2257 MONO_BB_FOR_EACH_INS_SAFE (bb, next, ins) {
2258 switch (ins->opcode) {
2259 case OP_DIV_IMM:
2260 case OP_REM_IMM:
2261 case OP_IDIV_IMM:
2262 case OP_IREM_IMM:
2263 case OP_IDIV_UN_IMM:
2264 case OP_IREM_UN_IMM:
2265 case OP_LAND_IMM:
2266 case OP_LOR_IMM:
2267 case OP_LREM_IMM:
2268 case OP_LXOR_IMM:
2269 case OP_LOCALLOC_IMM:
2270 mono_decompose_op_imm (cfg, bb, ins);
2271 break;
2272 case OP_LADD_IMM:
2273 if (!s390_is_imm16 (ins->inst_imm))
2274 /* This is created by the memcpy code which ignores is_inst_imm */
2275 mono_decompose_op_imm (cfg, bb, ins);
2276 break;
2277 default:
2278 break;
2282 bb->max_vreg = cfg->next_vreg;
2285 /*========================= End of Function ========================*/
2287 /*------------------------------------------------------------------*/
2288 /* */
2289 /* Name - emit_float_to_int */
2290 /* */
2291 /* Function - Create instructions which will convert a floating */
2292 /* point value to integer. */
2293 /* */
2294 /*------------------------------------------------------------------*/
2296 static guchar*
2297 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
2299 /* sreg is a float, dreg is an integer reg. */
2300 if (is_signed) {
2301 s390_cgebr (code, dreg, 5, sreg);
2302 switch (size) {
2303 case 1:
2304 s390_ltgr (code, dreg, dreg);
2305 s390_jnl (code, 4);
2306 s390_oill (code, dreg, 0x80);
2307 s390_lghi (code, s390_r0, 0xff);
2308 s390_ngr (code, dreg, s390_r0);
2309 break;
2310 case 2:
2311 s390_ltgr (code, dreg, dreg);
2312 s390_jnl (code, 4);
2313 s390_oill (code, dreg, 0x8000);
2314 s390_llill(code, s390_r0, 0xffff);
2315 s390_ngr (code, dreg, s390_r0);
2316 break;
2318 } else {
2319 short *o[1];
2320 S390_SET (code, s390_r13, 0x4f000000u);
2321 s390_ldgr (code, s390_f14, s390_r13);
2322 s390_ler (code, s390_f15, sreg);
2323 s390_cebr (code, s390_f15, s390_f14);
2324 s390_jl (code, 0); CODEPTR (code, o[0]);
2325 S390_SET (code, s390_r13, 0x4f800000u);
2326 s390_ldgr (code, s390_f14, s390_r13);
2327 s390_sebr (code, s390_f15, s390_f14);
2328 s390_cfebr (code, dreg, 7, s390_f15);
2329 s390_j (code, 4);
2330 PTRSLOT (code, o[0]);
2331 s390_cfebr (code, dreg, 5, sreg);
2332 switch (size) {
2333 case 1:
2334 s390_lghi (code, s390_r0, 0xff);
2335 s390_ngr (code, dreg, s390_r0);
2336 break;
2337 case 2:
2338 s390_llill(code, s390_r0, 0xffff);
2339 s390_ngr (code, dreg, s390_r0);
2340 break;
2343 return code;
2346 /*========================= End of Function ========================*/
2348 /*------------------------------------------------------------------*/
2349 /* */
2350 /* Name - emit_double_to_int */
2351 /* */
2352 /* Function - Create instructions which will convert a floating */
2353 /* point value to integer. */
2354 /* */
2355 /*------------------------------------------------------------------*/
2357 static guchar*
2358 emit_double_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
2360 /* sreg is a float, dreg is an integer reg. */
2361 if (is_signed) {
2362 s390_cgdbr (code, dreg, 5, sreg);
2363 switch (size) {
2364 case 1:
2365 s390_ltgr (code, dreg, dreg);
2366 s390_jnl (code, 4);
2367 s390_oill (code, dreg, 0x80);
2368 s390_lghi (code, s390_r0, 0xff);
2369 s390_ngr (code, dreg, s390_r0);
2370 break;
2371 case 2:
2372 s390_ltgr (code, dreg, dreg);
2373 s390_jnl (code, 4);
2374 s390_oill (code, dreg, 0x8000);
2375 s390_llill(code, s390_r0, 0xffff);
2376 s390_ngr (code, dreg, s390_r0);
2377 break;
2379 } else {
2380 short *o[1];
2381 S390_SET (code, s390_r13, 0x41e0000000000000llu);
2382 s390_ldgr (code, s390_f14, s390_r13);
2383 s390_ldr (code, s390_f15, sreg);
2384 s390_cdbr (code, s390_f15, s390_f14);
2385 s390_jl (code, 0); CODEPTR (code, o[0]);
2386 S390_SET (code, s390_r13, 0x41f0000000000000llu);
2387 s390_ldgr (code, s390_f14, s390_r13);
2388 s390_sdbr (code, s390_f15, s390_f14);
2389 s390_cfdbr (code, dreg, 7, s390_f15);
2390 s390_j (code, 4);
2391 PTRSLOT (code, o[0]);
2392 s390_cfdbr (code, dreg, 5, sreg);
2393 switch (size) {
2394 case 1:
2395 s390_lghi (code, s390_r0, 0xff);
2396 s390_ngr (code, dreg, s390_r0);
2397 break;
2398 case 2:
2399 s390_llill(code, s390_r0, 0xffff);
2400 s390_ngr (code, dreg, s390_r0);
2401 break;
2404 return code;
2407 /*========================= End of Function ========================*/
2409 /*------------------------------------------------------------------*/
2410 /* */
2411 /* Name - is_unsigned. */
2412 /* */
2413 /* Function - Return TRUE if next opcode is checking for un- */
2414 /* signed value. */
2415 /* */
2416 /*------------------------------------------------------------------*/
2418 static gboolean
2419 is_unsigned (MonoInst *next)
2421 if ((next) &&
2422 (((next->opcode >= OP_IBNE_UN) &&
2423 (next->opcode <= OP_IBLT_UN)) ||
2424 ((next->opcode >= OP_LBNE_UN) &&
2425 (next->opcode <= OP_LBLT_UN)) ||
2426 ((next->opcode >= OP_COND_EXC_NE_UN) &&
2427 (next->opcode <= OP_COND_EXC_LT_UN)) ||
2428 ((next->opcode >= OP_COND_EXC_INE_UN) &&
2429 (next->opcode <= OP_COND_EXC_ILT_UN)) ||
2430 ((next->opcode == OP_CLT_UN) ||
2431 (next->opcode == OP_CGT_UN) ||
2432 (next->opcode == OP_ICGE_UN) ||
2433 (next->opcode == OP_ICLE_UN)) ||
2434 ((next->opcode == OP_ICLT_UN) ||
2435 (next->opcode == OP_ICGT_UN) ||
2436 (next->opcode == OP_LCLT_UN) ||
2437 (next->opcode == OP_LCGT_UN))))
2438 return TRUE;
2439 else
2440 return FALSE;
2443 /*========================= End of Function ========================*/
2445 /*------------------------------------------------------------------*/
2446 /* */
2447 /* Name - mono_arch_output_basic_block */
2448 /* */
2449 /* Function - Perform the "real" work of emitting instructions */
2450 /* that will do the work of in the basic block. */
2451 /* */
2452 /*------------------------------------------------------------------*/
2454 void
2455 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2457 MonoInst *ins;
2458 MonoCallInst *call;
2459 guint8 *code = cfg->native_code + cfg->code_len;
2460 int src2;
2462 /* we don't align basic blocks of loops on s390 */
2464 if (cfg->verbose_level > 2)
2465 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
2467 MONO_BB_FOR_EACH_INS (bb, ins) {
2468 const guint offset = code - cfg->native_code;
2469 set_code_cursor (cfg, code);
2470 int max_len = ins_get_size (ins->opcode);
2471 code = realloc_code (cfg, max_len);
2473 mono_debug_record_line_number (cfg, ins, offset);
2475 switch (ins->opcode) {
2476 case OP_STOREI1_MEMBASE_IMM: {
2477 s390_lghi (code, s390_r0, ins->inst_imm);
2478 S390_LONG (code, stcy, stc, s390_r0, 0,
2479 ins->inst_destbasereg, ins->inst_offset);
2481 break;
2482 case OP_STOREI2_MEMBASE_IMM: {
2483 s390_lghi (code, s390_r0, ins->inst_imm);
2484 S390_LONG (code, sthy, sth, s390_r0, 0,
2485 ins->inst_destbasereg, ins->inst_offset);
2487 break;
2488 case OP_STOREI4_MEMBASE_IMM: {
2489 s390_lgfi (code, s390_r0, ins->inst_imm);
2490 S390_LONG (code, sty, st, s390_r0, 0,
2491 ins->inst_destbasereg, ins->inst_offset);
2493 break;
2494 case OP_STORE_MEMBASE_IMM:
2495 case OP_STOREI8_MEMBASE_IMM: {
2496 S390_SET (code, s390_r0, ins->inst_imm);
2497 S390_LONG (code, stg, stg, s390_r0, 0,
2498 ins->inst_destbasereg, ins->inst_offset);
2500 break;
2501 case OP_STOREI1_MEMBASE_REG: {
2502 S390_LONG (code, stcy, stc, ins->sreg1, 0,
2503 ins->inst_destbasereg, ins->inst_offset);
2505 break;
2506 case OP_STOREI2_MEMBASE_REG: {
2507 S390_LONG (code, sthy, sth, ins->sreg1, 0,
2508 ins->inst_destbasereg, ins->inst_offset);
2510 break;
2511 case OP_STOREI4_MEMBASE_REG: {
2512 S390_LONG (code, sty, st, ins->sreg1, 0,
2513 ins->inst_destbasereg, ins->inst_offset);
2515 break;
2516 case OP_STORE_MEMBASE_REG:
2517 case OP_STOREI8_MEMBASE_REG: {
2518 S390_LONG (code, stg, stg, ins->sreg1, 0,
2519 ins->inst_destbasereg, ins->inst_offset);
2521 break;
2522 case OP_LOADU4_MEM:
2523 g_assert_not_reached ();
2524 break;
2525 case OP_LOAD_MEMBASE:
2526 case OP_LOADI8_MEMBASE: {
2527 S390_LONG (code, lg, lg, ins->dreg, 0,
2528 ins->inst_basereg, ins->inst_offset);
2530 break;
2531 case OP_LOADI4_MEMBASE: {
2532 S390_LONG (code, lgf, lgf, ins->dreg, 0,
2533 ins->inst_basereg, ins->inst_offset);
2535 break;
2536 case OP_LOADU4_MEMBASE: {
2537 S390_LONG (code, llgf, llgf, ins->dreg, 0,
2538 ins->inst_basereg, ins->inst_offset);
2540 break;
2541 case OP_LOADU1_MEMBASE: {
2542 S390_LONG (code, llgc, llgc, ins->dreg, 0,
2543 ins->inst_basereg, ins->inst_offset);
2545 break;
2546 case OP_LOADI1_MEMBASE: {
2547 S390_LONG (code, lgb, lgb, ins->dreg, 0,
2548 ins->inst_basereg, ins->inst_offset);
2550 break;
2551 case OP_LOADU2_MEMBASE: {
2552 S390_LONG (code, llgh, llgh, ins->dreg, 0,
2553 ins->inst_basereg, ins->inst_offset);
2555 break;
2556 case OP_LOADI2_MEMBASE: {
2557 S390_LONG (code, lgh, lgh, ins->dreg, 0,
2558 ins->inst_basereg, ins->inst_offset);
2560 break;
2561 case OP_LCONV_TO_I1: {
2562 s390_lgbr (code, ins->dreg, ins->sreg1);
2564 break;
2565 case OP_LCONV_TO_I2: {
2566 s390_lghr (code, ins->dreg, ins->sreg1);
2568 break;
2569 case OP_LCONV_TO_U1: {
2570 s390_llgcr (code, ins->dreg, ins->sreg1);
2572 break;
2573 case OP_LCONV_TO_U2: {
2574 s390_llghr (code, ins->dreg, ins->sreg1);
2576 break;
2577 case OP_ICONV_TO_I1: {
2578 s390_lgbr (code, ins->dreg, ins->sreg1);
2580 break;
2581 case OP_ICONV_TO_I2: {
2582 s390_lghr (code, ins->dreg, ins->sreg1);
2584 break;
2585 case OP_ICONV_TO_U1: {
2586 s390_llgcr (code, ins->dreg, ins->sreg1);
2588 break;
2589 case OP_ICONV_TO_U2: {
2590 s390_llghr (code, ins->dreg, ins->sreg1);
2592 break;
2593 case OP_ICONV_TO_U4: {
2594 s390_llgfr (code, ins->dreg, ins->sreg1);
2596 break;
2597 case OP_ICONV_TO_I4: {
2598 s390_lgfr (code, ins->dreg, ins->sreg1);
2600 break;
2601 case OP_COMPARE:
2602 case OP_LCOMPARE: {
2603 if (is_unsigned (ins->next))
2604 s390_clgr (code, ins->sreg1, ins->sreg2);
2605 else
2606 s390_cgr (code, ins->sreg1, ins->sreg2);
2608 break;
2609 case OP_ICOMPARE: {
2610 if (is_unsigned (ins->next))
2611 s390_clr (code, ins->sreg1, ins->sreg2);
2612 else
2613 s390_cr (code, ins->sreg1, ins->sreg2);
2615 break;
2616 case OP_COMPARE_IMM:
2617 case OP_LCOMPARE_IMM: {
2618 gboolean branchUn = is_unsigned (ins->next);
2619 if ((ins->inst_imm == 0) && (!branchUn)) {
2620 s390_ltgr (code, ins->sreg1, ins->sreg1);
2621 } else {
2622 S390_SET (code, s390_r0, ins->inst_imm);
2623 if (branchUn)
2624 s390_clgr (code, ins->sreg1, s390_r0);
2625 else
2626 s390_cgr (code, ins->sreg1, s390_r0);
2629 break;
2630 case OP_ICOMPARE_IMM: {
2631 gboolean branchUn = is_unsigned (ins->next);
2632 if ((ins->inst_imm == 0) && (!branchUn)) {
2633 s390_ltr (code, ins->sreg1, ins->sreg1);
2634 } else {
2635 S390_SET (code, s390_r0, ins->inst_imm);
2636 if (branchUn)
2637 s390_clr (code, ins->sreg1, s390_r0);
2638 else
2639 s390_cr (code, ins->sreg1, s390_r0);
2642 break;
2643 case OP_BREAK: {
2644 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_ABS,
2645 mono_break);
2646 S390_CALL_TEMPLATE (code, s390_r14);
2648 break;
2649 case OP_ADDCC: {
2650 if (mono_hwcap_s390x_has_mlt) {
2651 s390_agrk (code, ins->dreg, ins->sreg1, ins->sreg2);
2652 } else {
2653 CHECK_SRCDST_COM;
2654 s390_agr (code, ins->dreg, src2);
2657 break;
2658 case OP_LADD: {
2659 if (mono_hwcap_s390x_has_mlt) {
2660 s390_agrk (code, ins->dreg, ins->sreg1, ins->sreg2);
2661 } else {
2662 CHECK_SRCDST_COM;
2663 s390_agr (code, ins->dreg, src2);
2666 break;
2667 case OP_ADC: {
2668 CHECK_SRCDST_COM;
2669 s390_alcgr (code, ins->dreg, src2);
2671 break;
2672 case OP_ADD_IMM: {
2673 if (mono_hwcap_s390x_has_mlt) {
2674 if (s390_is_imm16 (ins->inst_imm)) {
2675 s390_aghik(code, ins->dreg, ins->sreg1, ins->inst_imm);
2676 } else {
2677 S390_SET (code, s390_r0, ins->inst_imm);
2678 s390_agrk (code, ins->dreg, ins->sreg1, s390_r0);
2680 } else {
2681 if (ins->dreg != ins->sreg1) {
2682 s390_lgr (code, ins->dreg, ins->sreg1);
2684 if (s390_is_imm16 (ins->inst_imm)) {
2685 s390_aghi (code, ins->dreg, ins->inst_imm);
2686 } else if (s390_is_imm32 (ins->inst_imm)) {
2687 s390_agfi (code, ins->dreg, ins->inst_imm);
2688 } else {
2689 S390_SET (code, s390_r0, ins->inst_imm);
2690 s390_agr (code, ins->dreg, s390_r0);
2694 break;
2695 case OP_LADD_IMM: {
2696 if (ins->dreg != ins->sreg1) {
2697 s390_lgr (code, ins->dreg, ins->sreg1);
2699 if (s390_is_imm32 (ins->inst_imm)) {
2700 s390_agfi (code, ins->dreg, ins->inst_imm);
2701 } else {
2702 S390_SET (code, s390_r0, ins->inst_imm);
2703 s390_agr (code, ins->dreg, s390_r0);
2706 break;
2707 case OP_ADC_IMM: {
2708 if (ins->dreg != ins->sreg1) {
2709 s390_lgr (code, ins->dreg, ins->sreg1);
2711 if (s390_is_imm16 (ins->inst_imm)) {
2712 s390_lghi (code, s390_r0, ins->inst_imm);
2713 s390_alcgr (code, ins->dreg, s390_r0);
2714 } else {
2715 S390_SET (code, s390_r0, ins->inst_imm);
2716 s390_alcgr (code, ins->dreg, s390_r0);
2719 break;
2720 case OP_IADD_OVF:
2721 case OP_S390_IADD_OVF: {
2722 CHECK_SRCDST_COM;
2723 s390_ar (code, ins->dreg, src2);
2724 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_OV, "OverflowException");
2725 s390_lgfr (code, ins->dreg, ins->dreg);
2727 break;
2728 case OP_IADD_OVF_UN:
2729 case OP_S390_IADD_OVF_UN: {
2730 CHECK_SRCDST_COM;
2731 s390_algr (code, ins->dreg, src2);
2732 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_CY, "OverflowException");
2733 s390_llgfr (code, ins->dreg, ins->dreg);
2735 break;
2736 case OP_ADD_OVF_CARRY: {
2737 CHECK_SRCDST_COM;
2738 s390_lghi (code, s390_r0, 0);
2739 s390_lgr (code, s390_r1, s390_r0);
2740 s390_alcgr (code, s390_r0, s390_r1);
2741 s390_agr (code, ins->dreg, src2);
2742 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_OV, "OverflowException");
2743 s390_agr (code, ins->dreg, s390_r0);
2744 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_OV, "OverflowException");
2746 break;
2747 case OP_ADD_OVF_UN_CARRY: {
2748 CHECK_SRCDST_COM;
2749 s390_alcgr (code, ins->dreg, src2);
2750 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_CY, "OverflowException");
2752 break;
2753 case OP_SUBCC: {
2754 if (mono_hwcap_s390x_has_mlt) {
2755 s390_sgrk (code, ins->dreg, ins->sreg1, ins->sreg2);
2756 } else {
2757 CHECK_SRCDST_NCOM;
2758 s390_sgr (code, ins->dreg, src2);
2761 break;
2762 case OP_LSUB: {
2763 if (mono_hwcap_s390x_has_mlt) {
2764 s390_sgrk (code, ins->dreg, ins->sreg1, ins->sreg2);
2765 } else {
2766 CHECK_SRCDST_NCOM;
2767 s390_sgr (code, ins->dreg, src2);
2770 break;
2771 case OP_SBB: {
2772 CHECK_SRCDST_NCOM;
2773 s390_slbgr(code, ins->dreg, src2);
2775 break;
2776 case OP_SUB_IMM: {
2777 if (ins->dreg != ins->sreg1) {
2778 s390_lgr (code, ins->dreg, ins->sreg1);
2780 if (s390_is_imm16 (-ins->inst_imm)) {
2781 s390_aghi (code, ins->dreg, -ins->inst_imm);
2782 } else if (s390_is_imm32 (-ins->inst_imm)) {
2783 s390_slgfi (code, ins->dreg, ins->inst_imm);
2784 } else {
2785 S390_SET (code, s390_r0, ins->inst_imm);
2786 s390_slgr (code, ins->dreg, s390_r0);
2789 break;
2790 case OP_LSUB_IMM: {
2791 if (ins->dreg != ins->sreg1) {
2792 s390_lgr (code, ins->dreg, ins->sreg1);
2794 if (s390_is_imm16 (-ins->inst_imm)) {
2795 s390_aghi (code, ins->dreg, -ins->inst_imm);
2796 } else if (s390_is_imm32 (-ins->inst_imm)) {
2797 s390_slgfi (code, ins->dreg, ins->inst_imm);
2798 } else {
2799 S390_SET (code, s390_r0, ins->inst_imm);
2800 s390_slgr (code, ins->dreg, s390_r0);
2803 break;
2804 case OP_SBB_IMM: {
2805 if (ins->dreg != ins->sreg1) {
2806 s390_lgr (code, ins->dreg, ins->sreg1);
2808 if (s390_is_imm16 (-ins->inst_imm)) {
2809 s390_lghi (code, s390_r0, ins->inst_imm);
2810 s390_slbgr (code, ins->dreg, s390_r0);
2811 } else {
2812 S390_SET (code, s390_r0, ins->inst_imm);
2813 s390_slbgr(code, ins->dreg, s390_r0);
2816 break;
2817 case OP_SUB_OVF_CARRY: {
2818 CHECK_SRCDST_NCOM;
2819 s390_lghi (code, s390_r0, 0);
2820 s390_lgr (code, s390_r1, s390_r0);
2821 s390_slbgr (code, s390_r0, s390_r1);
2822 s390_sgr (code, ins->dreg, src2);
2823 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_OV, "OverflowException");
2824 s390_agr (code, ins->dreg, s390_r0);
2825 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_OV, "OverflowException");
2827 break;
2828 case OP_SUB_OVF_UN_CARRY: {
2829 CHECK_SRCDST_NCOM;
2830 s390_slbgr (code, ins->dreg, src2);
2831 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_NC, "OverflowException");
2833 break;
2834 case OP_LAND: {
2835 if (mono_hwcap_s390x_has_mlt) {
2836 s390_ngrk (code, ins->dreg, ins->sreg1, ins->sreg2);
2837 } else {
2838 if (ins->sreg1 == ins->dreg) {
2839 s390_ngr (code, ins->dreg, ins->sreg2);
2840 } else {
2841 if (ins->sreg2 == ins->dreg) {
2842 s390_ngr (code, ins->dreg, ins->sreg1);
2843 } else {
2844 s390_lgr (code, ins->dreg, ins->sreg1);
2845 s390_ngr (code, ins->dreg, ins->sreg2);
2850 break;
2851 case OP_AND_IMM: {
2852 S390_SET_MASK (code, s390_r0, ins->inst_imm);
2853 if (mono_hwcap_s390x_has_mlt) {
2854 s390_ngrk (code, ins->dreg, ins->sreg1, s390_r0);
2855 } else {
2856 if (ins->dreg != ins->sreg1) {
2857 s390_lgr (code, ins->dreg, ins->sreg1);
2859 s390_ngr (code, ins->dreg, s390_r0);
2862 break;
2863 case OP_LDIV: {
2864 s390_lgr (code, s390_r1, ins->sreg1);
2865 s390_dsgr (code, s390_r0, ins->sreg2);
2866 s390_lgr (code, ins->dreg, s390_r1);
2868 break;
2869 case OP_LDIV_UN: {
2870 s390_lgr (code, s390_r1, ins->sreg1);
2871 s390_lghi (code, s390_r0, 0);
2872 s390_dlgr (code, s390_r0, ins->sreg2);
2873 s390_lgr (code, ins->dreg, s390_r1);
2875 break;
2876 case OP_LREM: {
2877 s390_lgr (code, s390_r1, ins->sreg1);
2878 s390_dsgr (code, s390_r0, ins->sreg2);
2879 s390_lgr (code, ins->dreg, s390_r0);
2880 break;
2882 case OP_LREM_IMM: {
2883 if (s390_is_imm16 (ins->inst_imm)) {
2884 s390_lghi (code, s390_r13, ins->inst_imm);
2885 } else {
2886 s390_lgfi (code, s390_r13, ins->inst_imm);
2888 s390_lgr (code, s390_r0, ins->sreg1);
2889 s390_dsgr (code, s390_r0, s390_r13);
2890 s390_lgfr (code, ins->dreg, s390_r0);
2892 break;
2893 case OP_LREM_UN: {
2894 s390_lgr (code, s390_r1, ins->sreg1);
2895 s390_lghi (code, s390_r0, 0);
2896 s390_dlgr (code, s390_r0, ins->sreg2);
2897 s390_lgr (code, ins->dreg, s390_r0);
2899 break;
2900 case OP_LOR: {
2901 if (mono_hwcap_s390x_has_mlt) {
2902 s390_ogrk (code, ins->dreg, ins->sreg1, ins->sreg2);
2903 } else {
2904 if (ins->sreg1 == ins->dreg) {
2905 s390_ogr (code, ins->dreg, ins->sreg2);
2906 } else {
2907 if (ins->sreg2 == ins->dreg) {
2908 s390_ogr (code, ins->dreg, ins->sreg1);
2909 } else {
2910 s390_lgr (code, ins->dreg, ins->sreg1);
2911 s390_ogr (code, ins->dreg, ins->sreg2);
2916 break;
2917 case OP_OR_IMM: {
2918 S390_SET_MASK(code, s390_r0, ins->inst_imm);
2919 if (mono_hwcap_s390x_has_mlt) {
2920 s390_ogrk (code, ins->dreg, ins->sreg1, s390_r0);
2921 } else {
2922 if (ins->dreg != ins->sreg1) {
2923 s390_lgr (code, ins->dreg, ins->sreg1);
2925 s390_ogr (code, ins->dreg, s390_r0);
2928 break;
2929 case OP_LXOR: {
2930 if (mono_hwcap_s390x_has_mlt) {
2931 s390_xgrk (code, ins->dreg, ins->sreg1, ins->sreg2);
2932 } else {
2933 if (ins->sreg1 == ins->dreg) {
2934 s390_xgr (code, ins->dreg, ins->sreg2);
2936 else {
2937 if (ins->sreg2 == ins->dreg) {
2938 s390_xgr (code, ins->dreg, ins->sreg1);
2940 else {
2941 s390_lgr (code, ins->dreg, ins->sreg1);
2942 s390_xgr (code, ins->dreg, ins->sreg2);
2947 break;
2948 case OP_XOR_IMM: {
2949 S390_SET_MASK(code, s390_r0, ins->inst_imm);
2950 if (mono_hwcap_s390x_has_mlt) {
2951 s390_xgrk (code, ins->dreg, ins->sreg1, s390_r0);
2952 } else {
2953 if (ins->dreg != ins->sreg1) {
2954 s390_lgr (code, ins->dreg, ins->sreg1);
2956 s390_xgr (code, ins->dreg, s390_r0);
2959 break;
2960 case OP_LSHL: {
2961 CHECK_SRCDST_NCOM;
2962 s390_sllg (code, ins->dreg, ins->dreg, src2, 0);
2964 break;
2965 case OP_SHL_IMM:
2966 case OP_LSHL_IMM: {
2967 if (ins->sreg1 != ins->dreg) {
2968 s390_lgr (code, ins->dreg, ins->sreg1);
2970 s390_sllg (code, ins->dreg, ins->dreg, 0, (ins->inst_imm & 0x3f));
2972 break;
2973 case OP_LSHR: {
2974 CHECK_SRCDST_NCOM;
2975 s390_srag (code, ins->dreg, ins->dreg, src2, 0);
2977 break;
2978 case OP_SHR_IMM:
2979 case OP_LSHR_IMM: {
2980 if (ins->sreg1 != ins->dreg) {
2981 s390_lgr (code, ins->dreg, ins->sreg1);
2983 s390_srag (code, ins->dreg, ins->dreg, 0, (ins->inst_imm & 0x3f));
2985 break;
2986 case OP_SHR_UN_IMM:
2987 case OP_LSHR_UN_IMM: {
2988 if (ins->sreg1 != ins->dreg) {
2989 s390_lgr (code, ins->dreg, ins->sreg1);
2991 s390_srlg (code, ins->dreg, ins->dreg, 0, (ins->inst_imm & 0x3f));
2993 break;
2994 case OP_LSHR_UN: {
2995 CHECK_SRCDST_NCOM;
2996 s390_srlg (code, ins->dreg, ins->dreg, src2, 0);
2998 break;
2999 case OP_LNOT: {
3000 if (ins->sreg1 != ins->dreg) {
3001 s390_lgr (code, ins->dreg, ins->sreg1);
3003 s390_lghi (code, s390_r0, -1);
3004 s390_xgr (code, ins->dreg, s390_r0);
3006 break;
3007 case OP_LNEG: {
3008 s390_lcgr (code, ins->dreg, ins->sreg1);
3010 break;
3011 case OP_LMUL: {
3012 CHECK_SRCDST_COM;
3013 s390_msgr (code, ins->dreg, src2);
3015 break;
3016 case OP_MUL_IMM:
3017 case OP_LMUL_IMM: {
3018 if (ins->dreg != ins->sreg1) {
3019 s390_lgr (code, ins->dreg, ins->sreg1);
3021 if ((mono_hwcap_s390x_has_gie) &&
3022 (s390_is_imm32 (ins->inst_imm))) {
3023 s390_msgfi (code, ins->dreg, ins->inst_imm);
3024 } else {
3025 if (s390_is_imm16 (ins->inst_imm)) {
3026 s390_lghi (code, s390_r13, ins->inst_imm);
3027 } else if (s390_is_imm32 (ins->inst_imm)) {
3028 s390_lgfi (code, s390_r13, ins->inst_imm);
3029 } else {
3030 S390_SET (code, s390_r13, ins->inst_imm);
3032 s390_msgr (code, ins->dreg, s390_r13);
3035 break;
3036 case OP_LMUL_OVF: {
3037 short int *o[2];
3038 if (mono_hwcap_s390x_has_mie2) {
3039 s390_msgrkc (code, ins->dreg, ins->sreg1, ins->sreg2);
3040 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_OV, "OverflowException");
3041 } else {
3042 s390_ltgr (code, s390_r1, ins->sreg1);
3043 s390_jz (code, 0); CODEPTR(code, o[0]);
3044 s390_ltgr (code, s390_r0, ins->sreg2);
3045 s390_jnz (code, 6);
3046 s390_lghi (code, s390_r1, 0);
3047 s390_j (code, 0); CODEPTR(code, o[1]);
3048 s390_xgr (code, s390_r0, s390_r1);
3049 s390_msgr (code, s390_r1, ins->sreg2);
3050 s390_xgr (code, s390_r0, s390_r1);
3051 s390_srlg (code, s390_r0, s390_r0, 0, 63);
3052 s390_ltgr (code, s390_r0, s390_r0);
3053 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_NZ, "OverflowException");
3054 PTRSLOT (code, o[0]);
3055 PTRSLOT (code, o[1]);
3056 s390_lgr (code, ins->dreg, s390_r1);
3059 break;
3060 case OP_LMUL_OVF_UN: {
3061 s390_lghi (code, s390_r0, 0);
3062 s390_lgr (code, s390_r1, ins->sreg1);
3063 s390_mlgr (code, s390_r0, ins->sreg2);
3064 s390_ltgr (code, s390_r0, s390_r0);
3065 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_NZ, "OverflowException");
3066 s390_lgr (code, ins->dreg, s390_r1);
3068 break;
3069 case OP_IADDCC: {
3070 g_assert_not_reached ();
3071 CHECK_SRCDST_COM_I;
3072 s390_algr (code, ins->dreg, src2);
3074 break;
3075 case OP_IADD: {
3076 CHECK_SRCDST_COM_I;
3077 s390_agr (code, ins->dreg, src2);
3079 break;
3080 case OP_IADC: {
3081 g_assert_not_reached ();
3082 CHECK_SRCDST_COM_I;
3083 s390_alcgr (code, ins->dreg, src2);
3085 break;
3086 case OP_IADD_IMM: {
3087 if (ins->dreg != ins->sreg1) {
3088 s390_lgfr (code, ins->dreg, ins->sreg1);
3090 if (s390_is_imm16 (ins->inst_imm)) {
3091 s390_aghi (code, ins->dreg, ins->inst_imm);
3092 } else {
3093 s390_afi (code, ins->dreg, ins->inst_imm);
3096 break;
3097 case OP_IADC_IMM: {
3098 if (ins->dreg != ins->sreg1) {
3099 s390_lgfr (code, ins->dreg, ins->sreg1);
3101 if (s390_is_imm16 (ins->inst_imm)) {
3102 s390_lghi (code, s390_r0, ins->inst_imm);
3103 s390_alcgr (code, ins->dreg, s390_r0);
3104 } else {
3105 S390_SET (code, s390_r0, ins->inst_imm);
3106 s390_alcgr (code, ins->dreg, s390_r0);
3109 break;
3110 case OP_LADD_OVF:
3111 case OP_S390_LADD_OVF: {
3112 if (mono_hwcap_s390x_has_mlt) {
3113 s390_agrk (code, ins->dreg, ins->sreg1, ins->sreg2);
3114 } else {
3115 CHECK_SRCDST_COM;
3116 s390_agr (code, ins->dreg, src2);
3118 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_OV, "OverflowException");
3120 break;
3121 case OP_LADD_OVF_UN:
3122 case OP_S390_LADD_OVF_UN: {
3123 if (mono_hwcap_s390x_has_mlt) {
3124 s390_algrk (code, ins->dreg, ins->sreg1, ins->sreg2);
3125 } else {
3126 CHECK_SRCDST_COM;
3127 s390_algr (code, ins->dreg, src2);
3129 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_CY, "OverflowException");
3131 break;
3132 case OP_ISUBCC: {
3133 if (mono_hwcap_s390x_has_mlt) {
3134 s390_slgrk (code, ins->dreg, ins->sreg1, ins->sreg2);
3135 } else {
3136 CHECK_SRCDST_NCOM_I;
3137 s390_slgr (code, ins->dreg, src2);
3140 break;
3141 case OP_ISUB: {
3142 if (mono_hwcap_s390x_has_mlt) {
3143 s390_sgrk (code, ins->dreg, ins->sreg1, ins->sreg2);
3144 } else {
3145 CHECK_SRCDST_NCOM_I;
3146 s390_sgr (code, ins->dreg, src2);
3149 break;
3150 case OP_ISBB: {
3151 CHECK_SRCDST_NCOM_I;
3152 s390_slbgr (code, ins->dreg, src2);
3154 break;
3155 case OP_ISUB_IMM: {
3156 if (ins->dreg != ins->sreg1) {
3157 s390_lgfr (code, ins->dreg, ins->sreg1);
3159 if (s390_is_imm16 (-ins->inst_imm)) {
3160 s390_aghi (code, ins->dreg, -ins->inst_imm);
3161 } else {
3162 s390_agfi (code, ins->dreg, -ins->inst_imm);
3165 break;
3166 case OP_ISBB_IMM: {
3167 S390_SET (code, s390_r0, ins->inst_imm);
3168 s390_slgfr (code, ins->dreg, s390_r0);
3170 break;
3171 case OP_ISUB_OVF:
3172 case OP_S390_ISUB_OVF: {
3173 if (mono_hwcap_s390x_has_mlt) {
3174 s390_srk (code, ins->dreg, ins->sreg1, ins->sreg2);
3175 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_OV, "OverflowException");
3176 } else {
3177 CHECK_SRCDST_NCOM;
3178 s390_sr (code, ins->dreg, src2);
3179 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_OV, "OverflowException");
3180 s390_lgfr (code, ins->dreg, ins->dreg);
3183 break;
3184 case OP_ISUB_OVF_UN:
3185 case OP_S390_ISUB_OVF_UN: {
3186 if (mono_hwcap_s390x_has_mlt) {
3187 s390_slrk (code, ins->dreg, ins->sreg1, ins->sreg2);
3188 } else {
3189 CHECK_SRCDST_NCOM;
3190 s390_slr (code, ins->dreg, src2);
3192 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_NC, "OverflowException");
3193 s390_llgfr(code, ins->dreg, ins->dreg);
3195 break;
3196 case OP_LSUB_OVF:
3197 case OP_S390_LSUB_OVF: {
3198 if (mono_hwcap_s390x_has_mlt) {
3199 s390_sgrk (code, ins->dreg, ins->sreg1, ins->sreg2);
3200 } else {
3201 CHECK_SRCDST_NCOM;
3202 s390_sgr (code, ins->dreg, src2);
3204 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_OV, "OverflowException");
3206 break;
3207 case OP_LSUB_OVF_UN:
3208 case OP_S390_LSUB_OVF_UN: {
3209 CHECK_SRCDST_NCOM;
3210 s390_slgr (code, ins->dreg, src2);
3211 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_NC, "OverflowException");
3213 break;
3214 case OP_IAND: {
3215 if (mono_hwcap_s390x_has_mlt) {
3216 s390_ngrk (code, ins->dreg, ins->sreg1, ins->sreg2);
3217 } else {
3218 CHECK_SRCDST_NCOM_I;
3219 s390_ngr (code, ins->dreg, src2);
3222 break;
3223 case OP_IAND_IMM: {
3224 S390_SET_MASK (code, s390_r0, ins->inst_imm);
3225 if (mono_hwcap_s390x_has_mlt) {
3226 s390_ngrk (code, ins->dreg, ins->sreg1, s390_r0);
3227 } else {
3228 if (ins->dreg != ins->sreg1) {
3229 s390_lgfr (code, ins->dreg, ins->sreg1);
3231 s390_ngr (code, ins->dreg, s390_r0);
3234 break;
3235 case OP_IDIV: {
3236 s390_lgfr (code, s390_r0, ins->sreg1);
3237 s390_srda (code, s390_r0, 0, 32);
3238 s390_dr (code, s390_r0, ins->sreg2);
3239 s390_lgfr (code, ins->dreg, s390_r1);
3241 break;
3242 case OP_IDIV_UN: {
3243 s390_lgfr (code, s390_r0, ins->sreg1);
3244 s390_srdl (code, s390_r0, 0, 32);
3245 s390_dlr (code, s390_r0, ins->sreg2);
3246 s390_lgfr (code, ins->dreg, s390_r1);
3248 break;
3249 case OP_IDIV_IMM: {
3250 if (s390_is_imm16 (ins->inst_imm)) {
3251 s390_lghi (code, s390_r13, ins->inst_imm);
3252 } else {
3253 s390_lgfi (code, s390_r13, ins->inst_imm);
3255 s390_lgfr (code, s390_r0, ins->sreg1);
3256 s390_srda (code, s390_r0, 0, 32);
3257 s390_dr (code, s390_r0, ins->sreg2);
3258 s390_lgfr (code, ins->dreg, s390_r1);
3260 break;
3261 case OP_IREM: {
3262 s390_lgfr (code, s390_r0, ins->sreg1);
3263 s390_srda (code, s390_r0, 0, 32);
3264 s390_dr (code, s390_r0, ins->sreg2);
3265 s390_lgfr (code, ins->dreg, s390_r0);
3266 break;
3267 case OP_IREM_UN:
3268 s390_lgfr (code, s390_r0, ins->sreg1);
3269 s390_srdl (code, s390_r0, 0, 32);
3270 s390_dlr (code, s390_r0, ins->sreg2);
3271 s390_lgfr (code, ins->dreg, s390_r0);
3273 break;
3274 case OP_IREM_IMM: {
3275 if (s390_is_imm16 (ins->inst_imm)) {
3276 s390_lghi (code, s390_r13, ins->inst_imm);
3277 } else {
3278 s390_lgfi (code, s390_r13, ins->inst_imm);
3280 s390_lgfr (code, s390_r0, ins->sreg1);
3281 s390_srda (code, s390_r0, 0, 32);
3282 s390_dr (code, s390_r0, ins->sreg2);
3283 s390_lgfr (code, ins->dreg, s390_r0);
3285 break;
3286 case OP_IOR: {
3287 if (mono_hwcap_s390x_has_mlt) {
3288 s390_ogrk (code, ins->dreg, ins->sreg1, ins->sreg2);
3289 } else {
3290 CHECK_SRCDST_COM_I;
3291 s390_ogr (code, ins->dreg, src2);
3294 break;
3295 case OP_IOR_IMM: {
3296 S390_SET_MASK (code, s390_r0, ins->inst_imm);
3297 if (mono_hwcap_s390x_has_mlt) {
3298 s390_ogrk (code, ins->dreg, ins->sreg1, s390_r0);
3299 } else {
3300 if (ins->dreg != ins->sreg1) {
3301 s390_lgfr (code, ins->dreg, ins->sreg1);
3303 s390_ogr (code, ins->dreg, s390_r0);
3306 break;
3307 case OP_IXOR: {
3308 if (mono_hwcap_s390x_has_mlt) {
3309 s390_xgrk (code, ins->dreg, ins->sreg1, ins->sreg2);
3310 } else {
3311 CHECK_SRCDST_COM_I;
3312 s390_xgr (code, ins->dreg, src2);
3315 break;
3316 case OP_IXOR_IMM: {
3317 S390_SET_MASK (code, s390_r0, ins->inst_imm);
3318 if (mono_hwcap_s390x_has_mlt) {
3319 s390_xgrk (code, ins->dreg, ins->sreg1, s390_r0);
3320 } else {
3321 if (ins->dreg != ins->sreg1) {
3322 s390_lgfr (code, ins->dreg, ins->sreg1);
3324 s390_xgr (code, ins->dreg, s390_r0);
3327 break;
3328 case OP_ISHL: {
3329 CHECK_SRCDST_NCOM;
3330 s390_sll (code, ins->dreg, src2, 0);
3332 break;
3333 case OP_ISHL_IMM: {
3334 if (ins->sreg1 != ins->dreg) {
3335 s390_lgfr (code, ins->dreg, ins->sreg1);
3337 s390_sll (code, ins->dreg, 0, (ins->inst_imm & 0x1f));
3339 break;
3340 case OP_ISHR: {
3341 CHECK_SRCDST_NCOM;
3342 s390_sra (code, ins->dreg, src2, 0);
3344 break;
3345 case OP_ISHR_IMM: {
3346 if (ins->sreg1 != ins->dreg) {
3347 s390_lgfr (code, ins->dreg, ins->sreg1);
3349 s390_sra (code, ins->dreg, 0, (ins->inst_imm & 0x1f));
3351 break;
3352 case OP_ISHR_UN_IMM: {
3353 if (ins->sreg1 != ins->dreg) {
3354 s390_lgfr (code, ins->dreg, ins->sreg1);
3356 s390_srl (code, ins->dreg, 0, (ins->inst_imm & 0x1f));
3358 break;
3359 case OP_ISHR_UN: {
3360 CHECK_SRCDST_NCOM;
3361 s390_srl (code, ins->dreg, src2, 0);
3363 break;
3364 case OP_INOT: {
3365 if (ins->sreg1 != ins->dreg) {
3366 s390_lgfr (code, ins->dreg, ins->sreg1);
3368 s390_lghi (code, s390_r0, -1);
3369 s390_xgr (code, ins->dreg, s390_r0);
3371 break;
3372 case OP_INEG: {
3373 s390_lcgr (code, ins->dreg, ins->sreg1);
3375 break;
3376 case OP_IMUL: {
3377 CHECK_SRCDST_COM_I;
3378 s390_msr (code, ins->dreg, src2);
3380 break;
3381 case OP_IMUL_IMM: {
3382 if (ins->dreg != ins->sreg1) {
3383 s390_lgfr (code, ins->dreg, ins->sreg1);
3385 if (s390_is_imm16 (ins->inst_imm)) {
3386 s390_lghi (code, s390_r0, ins->inst_imm);
3387 } else {
3388 s390_lgfi (code, s390_r0, ins->inst_imm);
3390 s390_msr (code, ins->dreg, s390_r0);
3392 break;
3393 case OP_IMUL_OVF: {
3394 short int *o[2];
3395 s390_ltr (code, s390_r1, ins->sreg1);
3396 s390_jz (code, 0); CODEPTR(code, o[0]);
3397 s390_ltr (code, s390_r0, ins->sreg2);
3398 s390_jnz (code, 6);
3399 s390_lhi (code, s390_r1, 0);
3400 s390_j (code, 0); CODEPTR(code, o[1]);
3401 s390_xr (code, s390_r0, s390_r1);
3402 s390_msr (code, s390_r1, ins->sreg2);
3403 s390_xr (code, s390_r0, s390_r1);
3404 s390_srl (code, s390_r0, 0, 31);
3405 s390_ltr (code, s390_r0, s390_r0);
3406 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_NZ, "OverflowException");
3407 PTRSLOT (code, o[0]);
3408 PTRSLOT (code, o[1]);
3409 s390_lgfr (code, ins->dreg, s390_r1);
3411 break;
3412 case OP_IMUL_OVF_UN: {
3413 s390_lhi (code, s390_r0, 0);
3414 s390_lr (code, s390_r1, ins->sreg1);
3415 s390_mlr (code, s390_r0, ins->sreg2);
3416 s390_ltr (code, s390_r0, s390_r0);
3417 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_NZ, "OverflowException");
3418 s390_lgfr (code, ins->dreg, s390_r1);
3420 break;
3421 case OP_ICONST:
3422 case OP_I8CONST: {
3423 S390_SET (code, ins->dreg, ins->inst_c0);
3425 break;
3426 case OP_AOTCONST: {
3427 mono_add_patch_info (cfg, code - cfg->native_code,
3428 (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3429 S390_LOAD_TEMPLATE (code, ins->dreg);
3431 break;
3432 case OP_JUMP_TABLE: {
3433 mono_add_patch_info (cfg, code - cfg->native_code,
3434 (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3435 S390_LOAD_TEMPLATE (code, ins->dreg);
3437 break;
3438 case OP_MOVE:
3439 if (ins->dreg != ins->sreg1) {
3440 s390_lgr (code, ins->dreg, ins->sreg1);
3442 break;
3443 case OP_LCONV_TO_I:
3444 case OP_LCONV_TO_I8:
3445 case OP_SEXT_I4:
3446 s390_lgfr (code, ins->dreg, ins->sreg1);
3447 break;
3448 case OP_LCONV_TO_I4:
3449 s390_lgfr (code, ins->dreg, ins->sreg1);
3450 break;
3451 case OP_LCONV_TO_U:
3452 case OP_LCONV_TO_U8:
3453 case OP_LCONV_TO_U4:
3454 case OP_ZEXT_I4:
3455 s390_llgfr (code, ins->dreg, ins->sreg1);
3456 break;
3457 case OP_LCONV_TO_OVF_U4:
3458 S390_SET (code, s390_r0, 4294967295);
3459 s390_clgr (code, ins->sreg1, s390_r0);
3460 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_GT, "OverflowException");
3461 s390_ltgr (code, ins->sreg1, ins->sreg1);
3462 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_LT, "OverflowException");
3463 s390_llgfr(code, ins->dreg, ins->sreg1);
3464 break;
3465 case OP_LCONV_TO_OVF_I4_UN:
3466 S390_SET (code, s390_r0, 2147483647);
3467 s390_cgr (code, ins->sreg1, s390_r0);
3468 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_GT, "OverflowException");
3469 s390_ltgr (code, ins->sreg1, ins->sreg1);
3470 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_LT, "OverflowException");
3471 s390_lgfr (code, ins->dreg, ins->sreg1);
3472 break;
3473 case OP_FMOVE:
3474 if (ins->dreg != ins->sreg1) {
3475 s390_ldr (code, ins->dreg, ins->sreg1);
3477 break;
3478 case OP_MOVE_F_TO_I8:
3479 s390_lgdr (code, ins->dreg, ins->sreg1);
3480 break;
3481 case OP_MOVE_I8_TO_F:
3482 s390_ldgr (code, ins->dreg, ins->sreg1);
3483 break;
3484 case OP_MOVE_F_TO_I4:
3485 s390_ledbr (code, s390_f0, ins->sreg1);
3486 s390_lgdr (code, ins->dreg, s390_f0);
3487 s390_srag (code, ins->dreg, ins->dreg, 0, 32);
3488 break;
3489 case OP_MOVE_I4_TO_F:
3490 s390_slag (code, s390_r0, ins->sreg1, 0, 32);
3491 s390_ldgr (code, ins->dreg, s390_r0);
3492 if (!cfg->r4fp)
3493 s390_ldebr (code, ins->dreg, ins->dreg);
3494 break;
3495 case OP_FCONV_TO_R4:
3496 s390_ledbr (code, ins->dreg, ins->sreg1);
3497 if (!cfg->r4fp)
3498 s390_ldebr (code, ins->dreg, ins->dreg);
3499 break;
3500 case OP_S390_SETF4RET:
3501 if (!cfg->r4fp)
3502 s390_ledbr (code, ins->dreg, ins->sreg1);
3503 break;
3504 case OP_TLS_GET: {
3505 if (s390_is_imm16 (ins->inst_offset)) {
3506 s390_lghi (code, s390_r13, ins->inst_offset);
3507 } else if (s390_is_imm32 (ins->inst_offset)) {
3508 s390_lgfi (code, s390_r13, ins->inst_offset);
3509 } else {
3510 S390_SET (code, s390_r13, ins->inst_offset);
3512 s390_ear (code, s390_r1, 0);
3513 s390_sllg(code, s390_r1, s390_r1, 0, 32);
3514 s390_ear (code, s390_r1, 1);
3515 s390_lg (code, ins->dreg, s390_r13, s390_r1, 0);
3517 break;
3518 case OP_TLS_SET: {
3519 if (s390_is_imm16 (ins->inst_offset)) {
3520 s390_lghi (code, s390_r13, ins->inst_offset);
3521 } else if (s390_is_imm32 (ins->inst_offset)) {
3522 s390_lgfi (code, s390_r13, ins->inst_offset);
3523 } else {
3524 S390_SET (code, s390_r13, ins->inst_offset);
3526 s390_ear (code, s390_r1, 0);
3527 s390_sllg(code, s390_r1, s390_r1, 0, 32);
3528 s390_ear (code, s390_r1, 1);
3529 s390_stg (code, ins->sreg1, s390_r13, s390_r1, 0);
3531 break;
3532 case OP_TAILCALL_PARAMETER :
3533 // This opcode helps compute sizes, i.e.
3534 // of the subsequent OP_TAILCALL, but contributes no code.
3535 g_assert (ins->next);
3536 break;
3537 case OP_TAILCALL :
3538 case OP_TAILCALL_MEMBASE : {
3539 MonoCallInst *call = (MonoCallInst *) ins;
3540 MonoMethod *method = call->method;
3541 MonoMethodSignature *sig = mono_method_signature_internal (method);
3542 CallInfo *cinfo = get_call_info (NULL, sig);
3543 int32_t stackUsage = (cinfo->sz.stack_size - S390_MINIMAL_STACK_SIZE),
3544 stackOffset = S390_MINIMAL_STACK_SIZE;
3546 if (cfg->method->save_lmf)
3547 restoreLMF(code, cfg->frame_reg, cfg->stack_usage);
3549 s390_lgr (code, s390_r12, cfg->frame_reg);
3550 code = backUpStackPtr(cfg, code);
3552 while (stackUsage > 256) {
3553 s390_mvc (code, 256, STK_BASE, stackOffset,
3554 s390_r12, stackOffset);
3555 stackUsage -= 256;
3556 stackOffset += 256;
3559 if (stackUsage > 0)
3560 s390_mvc (code, stackUsage, STK_BASE, stackOffset,
3561 s390_r12, stackOffset);
3563 s390_lmg (code, s390_r6, s390_r13, STK_BASE, S390_REG_SAVE_OFFSET);
3565 if (cfg->arch.used_fp_regs != 0) {
3566 int32_t fpOffset = sizeof(double);
3567 for (int i=8; i<16; i++) {
3568 if (cfg->arch.used_fp_regs & (1 << i)) {
3569 s390_ld (code, i, cfg->arch.fpSize, STK_BASE, fpOffset);
3570 fpOffset += sizeof(double);
3575 s390_lg (code, s390_r14, 0, STK_BASE, S390_RET_ADDR_OFFSET);
3576 if (ins->opcode == OP_TAILCALL_MEMBASE) {
3577 if (mono_hwcap_s390x_has_mie2) {
3578 s390_bi (code, 0, ins->sreg1, ins->inst_offset);
3579 } else {
3580 s390_lg (code, s390_r1, 0, ins->sreg1, ins->inst_offset);
3581 s390_br (code, s390_r1);
3583 } else {
3584 mono_add_patch_info (cfg, code - cfg->native_code,
3585 MONO_PATCH_INFO_METHOD_JUMP,
3586 call->method);
3587 s390_jcl (code, S390_CC_UN, 0);
3590 g_free (cinfo);
3592 break;
3593 case OP_CHECK_THIS: {
3594 /* ensure ins->sreg1 is not NULL */
3595 s390_lg (code, s390_r0, 0, ins->sreg1, 0);
3596 s390_ltgr (code, s390_r0, s390_r0);
3597 // EMIT_COND_SYSTEM_EXCEPTION (S390_CC_ZR, "NullReferenceException");
3599 break;
3600 case OP_ARGLIST: {
3601 const int offset = cfg->sig_cookie + cfg->stack_usage;
3603 if (s390_is_imm16 (offset)) {
3604 s390_lghi (code, s390_r0, offset);
3605 } else if (s390_is_imm32 (offset)) {
3606 s390_lgfi (code, s390_r0, offset);
3607 } else {
3608 S390_SET (code, s390_r0, offset);
3610 s390_agr (code, s390_r0, cfg->frame_reg);
3611 s390_stg (code, s390_r0, 0, ins->sreg1, 0);
3613 break;
3614 case OP_FCALL: {
3615 call = (MonoCallInst*)ins;
3616 if (ins->flags & MONO_INST_HAS_METHOD)
3617 mono_add_patch_info (cfg, code-cfg->native_code,
3618 MONO_PATCH_INFO_METHOD,
3619 call->method);
3620 else
3621 mono_add_patch_info (cfg, code-cfg->native_code,
3622 MONO_PATCH_INFO_ABS,
3623 call->fptr);
3624 S390_CALL_TEMPLATE (code, s390_r14);
3625 if (!cfg->r4fp && call->signature->ret->type == MONO_TYPE_R4)
3626 s390_ldebr (code, s390_f0, s390_f0);
3628 break;
3629 case OP_LCALL:
3630 case OP_VCALL:
3631 case OP_VCALL2:
3632 case OP_VOIDCALL:
3633 case OP_RCALL:
3634 case OP_CALL: {
3635 call = (MonoCallInst*)ins;
3636 mono_call_add_patch_info (cfg, call, code - cfg->native_code);
3637 S390_CALL_TEMPLATE (code, s390_r14);
3639 break;
3640 case OP_FCALL_REG: {
3641 call = (MonoCallInst*)ins;
3642 s390_lgr (code, s390_r1, ins->sreg1);
3643 s390_basr (code, s390_r14, s390_r1);
3644 if (!cfg->r4fp && call->signature->ret->type == MONO_TYPE_R4)
3645 s390_ldebr (code, s390_f0, s390_f0);
3647 break;
3648 case OP_LCALL_REG:
3649 case OP_VCALL_REG:
3650 case OP_VCALL2_REG:
3651 case OP_VOIDCALL_REG:
3652 case OP_RCALL_REG:
3653 case OP_CALL_REG: {
3654 s390_lgr (code, s390_r1, ins->sreg1);
3655 s390_basr (code, s390_r14, s390_r1);
3657 break;
3658 case OP_FCALL_MEMBASE: {
3659 call = (MonoCallInst*)ins;
3660 s390_lg (code, s390_r1, 0, ins->sreg1, ins->inst_offset);
3661 s390_basr (code, s390_r14, s390_r1);
3662 if (!cfg->r4fp && call->signature->ret->type == MONO_TYPE_R4)
3663 s390_ldebr (code, s390_f0, s390_f0);
3665 break;
3666 case OP_LCALL_MEMBASE:
3667 case OP_VCALL_MEMBASE:
3668 case OP_VCALL2_MEMBASE:
3669 case OP_VOIDCALL_MEMBASE:
3670 case OP_RCALL_MEMBASE:
3671 case OP_CALL_MEMBASE: {
3672 s390_lg (code, s390_r1, 0, ins->sreg1, ins->inst_offset);
3673 s390_basr (code, s390_r14, s390_r1);
3675 break;
3676 case OP_LOCALLOC: {
3677 int alloca_skip;
3678 int area_offset;
3680 if (cfg->param_area == 0)
3681 alloca_skip = S390_MINIMAL_STACK_SIZE;
3682 else
3683 alloca_skip = cfg->param_area;
3685 area_offset = S390_ALIGN(alloca_skip, S390_STACK_ALIGNMENT);
3686 s390_lgr (code, s390_r1, ins->sreg1);
3687 if (ins->flags & MONO_INST_INIT)
3688 s390_lgr (code, s390_r0, ins->sreg1);
3689 s390_aghi (code, s390_r1, 14);
3690 s390_srlg (code, s390_r1, s390_r1, 0, 3);
3691 s390_sllg (code, s390_r1, s390_r1, 0, 3);
3692 if (cfg->method->save_lmf) {
3693 /*----------------------------------*/
3694 /* we have to adjust lmf ebp value */
3695 /*----------------------------------*/
3696 int lmfOffset = cfg->stack_usage - sizeof(MonoLMF);
3698 s390_lgr (code, s390_r13, cfg->frame_reg);
3699 if (s390_is_imm16(lmfOffset)) {
3700 s390_aghi (code, s390_r13, lmfOffset);
3701 } else if (s390_is_imm32(lmfOffset)) {
3702 s390_agfi (code, s390_r13, lmfOffset);
3703 } else {
3704 S390_SET (code, s390_r13, lmfOffset);
3706 s390_lgr (code, s390_r14, STK_BASE);
3707 s390_sgr (code, s390_r14, s390_r1);
3708 s390_stg (code, s390_r14, 0, s390_r13,
3709 G_STRUCT_OFFSET(MonoLMF, ebp));
3711 s390_lg (code, s390_r13, 0, STK_BASE, 0);
3712 s390_sgr (code, STK_BASE, s390_r1);
3713 s390_stg (code, s390_r13, 0, STK_BASE, 0);
3714 s390_la (code, ins->dreg, 0, STK_BASE, area_offset);
3715 s390_srlg (code, ins->dreg, ins->dreg, 0, 3);
3716 s390_sllg (code, ins->dreg, ins->dreg, 0, 3);
3717 if (ins->flags & MONO_INST_INIT) {
3718 s390_lgr (code, s390_r1, s390_r0);
3719 s390_lgr (code, s390_r0, ins->dreg);
3720 s390_lgr (code, s390_r14, s390_r12);
3721 s390_lghi (code, s390_r13, 0);
3722 s390_mvcle(code, s390_r0, s390_r12, 0, 0);
3723 s390_jo (code, -2);
3724 s390_lgr (code, s390_r12, s390_r14);
3727 break;
3728 case OP_THROW: {
3729 s390_lgr (code, s390_r2, ins->sreg1);
3730 mono_add_patch_info (cfg, code-cfg->native_code, MONO_PATCH_INFO_JIT_ICALL_ID,
3731 GUINT_TO_POINTER (MONO_JIT_ICALL_mono_arch_throw_exception));
3732 S390_CALL_TEMPLATE(code, s390_r14);
3734 break;
3735 case OP_RETHROW: {
3736 s390_lgr (code, s390_r2, ins->sreg1);
3737 mono_add_patch_info (cfg, code-cfg->native_code, MONO_PATCH_INFO_JIT_ICALL_ID,
3738 GUINT_TO_POINTER (MONO_JIT_ICALL_mono_arch_rethrow_exception));
3739 S390_CALL_TEMPLATE(code, s390_r14);
3741 break;
3742 case OP_START_HANDLER: {
3743 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3745 S390_LONG (code, stg, stg, s390_r14, 0,
3746 spvar->inst_basereg,
3747 spvar->inst_offset);
3749 break;
3750 case OP_ENDFILTER: {
3751 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3753 if (ins->sreg1 != s390_r2)
3754 s390_lgr(code, s390_r2, ins->sreg1);
3755 S390_LONG (code, lg, lg, s390_r14, 0,
3756 spvar->inst_basereg,
3757 spvar->inst_offset);
3758 s390_br (code, s390_r14);
3760 break;
3761 case OP_ENDFINALLY: {
3762 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3764 S390_LONG (code, lg, lg, s390_r14, 0,
3765 spvar->inst_basereg,
3766 spvar->inst_offset);
3767 s390_br (code, s390_r14);
3769 break;
3770 case OP_CALL_HANDLER: {
3771 mono_add_patch_info (cfg, code-cfg->native_code,
3772 MONO_PATCH_INFO_BB, ins->inst_target_bb);
3773 s390_brasl (code, s390_r14, 0);
3774 for (GList *tmp = ins->inst_eh_blocks; tmp != bb->clause_holes; tmp = tmp->prev)
3775 mono_cfg_add_try_hole (cfg, ((MonoLeaveClause *) tmp->data)->clause, code, bb);
3777 break;
3778 case OP_LABEL: {
3779 ins->inst_c0 = code - cfg->native_code;
3781 break;
3782 case OP_RELAXED_NOP:
3783 case OP_NOP:
3784 case OP_DUMMY_USE:
3785 case OP_DUMMY_ICONST:
3786 case OP_DUMMY_I8CONST:
3787 case OP_DUMMY_R8CONST:
3788 case OP_DUMMY_R4CONST:
3789 case OP_NOT_REACHED:
3790 case OP_NOT_NULL: {
3792 break;
3793 case OP_IL_SEQ_POINT:
3794 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3795 break;
3796 case OP_SEQ_POINT: {
3797 int i;
3799 if (cfg->compile_aot)
3800 NOT_IMPLEMENTED;
3803 * Read from the single stepping trigger page. This will cause a
3804 * SIGSEGV when single stepping is enabled.
3805 * We do this _before_ the breakpoint, so single stepping after
3806 * a breakpoint is hit will step to the next IL offset.
3808 if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
3809 breakpointCode.pTrigger = ss_trigger_page;
3810 memcpy(code, (void *) &breakpointCode, BREAKPOINT_SIZE);
3811 code += BREAKPOINT_SIZE;
3814 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3817 * A placeholder for a possible breakpoint inserted by
3818 * mono_arch_set_breakpoint ().
3820 for (i = 0; i < (BREAKPOINT_SIZE / S390X_NOP_SIZE); ++i)
3821 s390_nop (code);
3824 * Add an additional nop so skipping the bp doesn't cause the ip to point
3825 * to another IL offset.
3827 s390_nop (code);
3829 break;
3831 case OP_GENERIC_CLASS_INIT: {
3832 static int byte_offset = -1;
3833 static guint8 bitmask;
3834 short int *jump;
3836 g_assert (ins->sreg1 == S390_FIRST_ARG_REG);
3838 if (byte_offset < 0)
3839 mono_marshal_find_bitfield_offset (MonoVTable, initialized, &byte_offset, &bitmask);
3841 s390_tm (code, ins->sreg1, byte_offset, bitmask);
3842 s390_jo (code, 0); CODEPTR(code, jump);
3844 mono_add_patch_info (cfg, code-cfg->native_code, MONO_PATCH_INFO_JIT_ICALL_ID,
3845 GUINT_TO_POINTER (MONO_JIT_ICALL_mono_generic_class_init));
3846 S390_CALL_TEMPLATE(code, s390_r14);
3848 PTRSLOT (code, jump);
3850 ins->flags |= MONO_INST_GC_CALLSITE;
3851 ins->backend.pc_offset = code - cfg->native_code;
3852 break;
3854 case OP_BR:
3855 EMIT_UNCOND_BRANCH(ins);
3856 break;
3857 case OP_BR_REG: {
3858 s390_br (code, ins->sreg1);
3860 break;
3861 case OP_CEQ:
3862 case OP_ICEQ:
3863 case OP_LCEQ: {
3864 s390_lghi(code, ins->dreg, 1);
3865 s390_jz (code, 4);
3866 s390_lghi(code, ins->dreg, 0);
3868 break;
3869 case OP_CLT:
3870 case OP_ICLT:
3871 case OP_LCLT: {
3872 s390_lghi(code, ins->dreg, 1);
3873 s390_jl (code, 4);
3874 s390_lghi(code, ins->dreg, 0);
3876 break;
3877 case OP_CLT_UN:
3878 case OP_ICLT_UN:
3879 case OP_LCLT_UN: {
3880 s390_lghi(code, ins->dreg, 1);
3881 s390_jlo (code, 4);
3882 s390_lghi(code, ins->dreg, 0);
3884 break;
3885 case OP_CGT:
3886 case OP_ICGT:
3887 case OP_LCGT: {
3888 s390_lghi(code, ins->dreg, 1);
3889 s390_jh (code, 4);
3890 s390_lghi(code, ins->dreg, 0);
3892 break;
3893 case OP_CGT_UN:
3894 case OP_ICGT_UN:
3895 case OP_LCGT_UN: {
3896 s390_lghi(code, ins->dreg, 1);
3897 s390_jho (code, 4);
3898 s390_lghi(code, ins->dreg, 0);
3900 break;
3901 case OP_ICNEQ: {
3902 s390_lghi(code, ins->dreg, 1);
3903 s390_jne (code, 4);
3904 s390_lghi(code, ins->dreg, 0);
3906 break;
3907 case OP_ICGE: {
3908 s390_lghi(code, ins->dreg, 1);
3909 s390_jhe (code, 4);
3910 s390_lghi(code, ins->dreg, 0);
3912 break;
3913 case OP_ICLE: {
3914 s390_lghi(code, ins->dreg, 1);
3915 s390_jle (code, 4);
3916 s390_lghi(code, ins->dreg, 0);
3918 break;
3919 case OP_ICGE_UN: {
3920 s390_lghi(code, ins->dreg, 1);
3921 s390_jhe (code, 4);
3922 s390_lghi(code, ins->dreg, 0);
3924 break;
3925 case OP_ICLE_UN: {
3926 s390_lghi(code, ins->dreg, 1);
3927 s390_jle (code, 4);
3928 s390_lghi(code, ins->dreg, 0);
3930 break;
3931 case OP_COND_EXC_EQ:
3932 case OP_COND_EXC_IEQ:
3933 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_EQ, ins->inst_p1);
3934 break;
3935 case OP_COND_EXC_NE_UN:
3936 case OP_COND_EXC_INE_UN:
3937 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_NE, ins->inst_p1);
3938 break;
3939 case OP_COND_EXC_LT:
3940 case OP_COND_EXC_ILT:
3941 case OP_COND_EXC_LT_UN:
3942 case OP_COND_EXC_ILT_UN:
3943 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_LT, ins->inst_p1);
3944 break;
3945 case OP_COND_EXC_GT:
3946 case OP_COND_EXC_IGT:
3947 case OP_COND_EXC_GT_UN:
3948 case OP_COND_EXC_IGT_UN:
3949 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_GT, ins->inst_p1);
3950 break;
3951 case OP_COND_EXC_GE:
3952 case OP_COND_EXC_IGE:
3953 case OP_COND_EXC_GE_UN:
3954 case OP_COND_EXC_IGE_UN:
3955 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_GE, ins->inst_p1);
3956 break;
3957 case OP_COND_EXC_LE:
3958 case OP_COND_EXC_ILE:
3959 case OP_COND_EXC_LE_UN:
3960 case OP_COND_EXC_ILE_UN:
3961 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_LE, ins->inst_p1);
3962 break;
3963 case OP_COND_EXC_OV:
3964 case OP_COND_EXC_IOV:
3965 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_OV, ins->inst_p1);
3966 break;
3967 case OP_COND_EXC_NO:
3968 case OP_COND_EXC_INO:
3969 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_NO, ins->inst_p1);
3970 break;
3971 case OP_COND_EXC_C:
3972 case OP_COND_EXC_IC:
3973 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_CY, ins->inst_p1);
3974 break;
3975 case OP_COND_EXC_NC:
3976 case OP_COND_EXC_INC:
3977 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_NC, ins->inst_p1);
3978 break;
3979 case OP_LBEQ:
3980 case OP_IBEQ:
3981 EMIT_COND_BRANCH (ins, S390_CC_EQ);
3982 break;
3983 case OP_LBNE_UN:
3984 case OP_IBNE_UN:
3985 EMIT_COND_BRANCH (ins, S390_CC_NE);
3986 break;
3987 case OP_LBLT:
3988 case OP_LBLT_UN:
3989 case OP_IBLT:
3990 case OP_IBLT_UN:
3991 EMIT_COND_BRANCH (ins, S390_CC_LT);
3992 break;
3993 case OP_LBGT:
3994 case OP_LBGT_UN:
3995 case OP_IBGT:
3996 case OP_IBGT_UN:
3997 EMIT_COND_BRANCH (ins, S390_CC_GT);
3998 break;
3999 case OP_LBGE:
4000 case OP_LBGE_UN:
4001 case OP_IBGE:
4002 case OP_IBGE_UN:
4003 EMIT_COND_BRANCH (ins, S390_CC_GE);
4004 break;
4005 case OP_LBLE:
4006 case OP_LBLE_UN:
4007 case OP_IBLE:
4008 case OP_IBLE_UN:
4009 EMIT_COND_BRANCH (ins, S390_CC_LE);
4010 break;
4012 case OP_S390_CRJ:
4013 EMIT_COMP_AND_BRANCH(ins, crj, cr);
4014 break;
4016 case OP_S390_CLRJ:
4017 EMIT_COMP_AND_BRANCH(ins, clrj, clr);
4018 break;
4020 case OP_S390_CGRJ:
4021 EMIT_COMP_AND_BRANCH(ins, cgrj, cgr);
4022 break;
4024 case OP_S390_CLGRJ:
4025 EMIT_COMP_AND_BRANCH(ins, clgrj, clgr);
4026 break;
4028 case OP_S390_CIJ:
4029 EMIT_COMP_AND_BRANCH_IMM(ins, crj, cr, ltr, FALSE);
4030 break;
4032 case OP_S390_CLIJ:
4033 EMIT_COMP_AND_BRANCH_IMM(ins, clrj, clr, ltr, TRUE);
4034 break;
4036 case OP_S390_CGIJ:
4037 EMIT_COMP_AND_BRANCH_IMM(ins, cgrj, cgr, ltgr, FALSE);
4038 break;
4040 case OP_S390_CLGIJ:
4041 EMIT_COMP_AND_BRANCH_IMM(ins, clgrj, clgr, ltgr, TRUE);
4042 break;
4044 /* floating point opcodes */
4045 case OP_R8CONST: {
4046 if (*((double *) ins->inst_p0) == 0) {
4047 s390_lzdr (code, ins->dreg);
4048 } else {
4049 S390_SET (code, s390_r13, ins->inst_p0);
4050 s390_ld (code, ins->dreg, 0, s390_r13, 0);
4053 break;
4054 case OP_R4CONST: {
4055 if (*((float *) ins->inst_p0) == 0) {
4056 if (cfg->r4fp)
4057 s390_lzer (code, ins->dreg);
4058 else
4059 s390_lzdr (code, ins->dreg);
4060 } else {
4061 S390_SET (code, s390_r13, ins->inst_p0);
4062 if (cfg->r4fp) {
4063 S390_LONG (code, ley, le, ins->dreg, 0, s390_r13, 0);
4064 } else {
4065 s390_ldeb (code, ins->dreg, 0, s390_r13, 0);
4069 break;
4070 case OP_STORER8_MEMBASE_REG: {
4071 S390_LONG (code, stdy, std, ins->sreg1, 0,
4072 ins->inst_destbasereg, ins->inst_offset);
4074 break;
4075 case OP_LOADR8_MEMBASE: {
4076 S390_LONG (code, ldy, ld, ins->dreg, 0,
4077 ins->inst_basereg, ins->inst_offset);
4079 break;
4080 case OP_STORER4_MEMBASE_REG: {
4081 if (cfg->r4fp) {
4082 S390_LONG (code, stey, ste, ins->sreg1, 0,
4083 ins->inst_destbasereg, ins->inst_offset);
4084 } else {
4085 s390_ledbr (code, s390_f15, ins->sreg1);
4086 S390_LONG (code, stey, ste, s390_f15, 0,
4087 ins->inst_destbasereg, ins->inst_offset);
4090 break;
4091 case OP_LOADR4_MEMBASE: {
4092 if (cfg->r4fp) {
4093 S390_LONG (code, ley, le, ins->dreg, 0,
4094 ins->inst_basereg, ins->inst_offset);
4095 } else {
4096 S390_LONG (code, ley, le, s390_f15, 0,
4097 ins->inst_basereg, ins->inst_offset);
4098 s390_ldebr (code, ins->dreg, s390_f15);
4101 break;
4102 case OP_ICONV_TO_R_UN: {
4103 if (mono_hwcap_s390x_has_fpe) {
4104 s390_cdlfbr (code, ins->dreg, 5, ins->sreg1, 0);
4105 } else {
4106 s390_llgfr (code, s390_r0, ins->sreg1);
4107 s390_cdgbr (code, ins->dreg, s390_r0);
4110 break;
4111 case OP_LCONV_TO_R_UN: {
4112 if (mono_hwcap_s390x_has_fpe) {
4113 s390_cdlgbr (code, ins->dreg, 5, ins->sreg1, 0);
4114 } else {
4115 short int *jump;
4116 s390_cxgbr (code, s390_f12, ins->sreg1);
4117 s390_ltgr (code, ins->sreg1, ins->sreg1);
4118 s390_jnl (code, 0); CODEPTR(code, jump);
4119 S390_SET (code, s390_r13, 0x403f000000000000llu);
4120 s390_lgdr (code, s390_f13, s390_r13);
4121 s390_lzdr (code, s390_f15);
4122 s390_axbr (code, s390_f12, s390_f13);
4123 PTRSLOT(code, jump);
4124 s390_ldxbr (code, s390_f13, s390_f12);
4125 s390_ldr (code, ins->dreg, s390_f13);
4128 break;
4129 case OP_LCONV_TO_R4:
4130 case OP_ICONV_TO_R4: {
4131 s390_cegbr (code, ins->dreg, ins->sreg1);
4132 if (!cfg->r4fp)
4133 s390_ldebr (code, ins->dreg, ins->dreg);
4135 break;
4136 case OP_LCONV_TO_R8:
4137 case OP_ICONV_TO_R8: {
4138 s390_cdgbr (code, ins->dreg, ins->sreg1);
4140 break;
4141 case OP_FCONV_TO_I1:
4142 s390_cgdbr (code, ins->dreg, 5, ins->sreg1);
4143 s390_ltgr (code, ins->dreg, ins->dreg);
4144 s390_jnl (code, 4);
4145 s390_oill (code, ins->dreg, 0x80);
4146 s390_lghi (code, s390_r0, 0xff);
4147 s390_ngr (code, ins->dreg, s390_r0);
4148 break;
4149 case OP_FCONV_TO_U1:
4150 if (mono_hwcap_s390x_has_fpe) {
4151 s390_clgdbr (code, ins->dreg, 5, ins->sreg1, 0);
4152 s390_lghi (code, s390_r0, 0xff);
4153 s390_ngr (code, ins->dreg, s390_r0);
4154 } else {
4155 code = emit_double_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4157 break;
4158 case OP_FCONV_TO_I2:
4159 s390_cgdbr (code, ins->dreg, 5, ins->sreg1);
4160 s390_ltgr (code, ins->dreg, ins->dreg);
4161 s390_jnl (code, 4);
4162 s390_oill (code, ins->dreg, 0x8000);
4163 s390_llill (code, s390_r0, 0xffff);
4164 s390_ngr (code, ins->dreg, s390_r0);
4165 break;
4166 case OP_FCONV_TO_U2:
4167 if (mono_hwcap_s390x_has_fpe) {
4168 s390_clgdbr (code, ins->dreg, 5, ins->sreg1, 0);
4169 s390_llill (code, s390_r0, 0xffff);
4170 s390_ngr (code, ins->dreg, s390_r0);
4171 } else {
4172 code = emit_double_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4174 break;
4175 case OP_FCONV_TO_I4:
4176 case OP_FCONV_TO_I:
4177 s390_cfdbr (code, ins->dreg, 5, ins->sreg1);
4178 break;
4179 case OP_FCONV_TO_U4:
4180 case OP_FCONV_TO_U:
4181 if (mono_hwcap_s390x_has_fpe) {
4182 s390_clfdbr (code, ins->dreg, 5, ins->sreg1, 0);
4183 } else {
4184 code = emit_double_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4186 break;
4187 case OP_FCONV_TO_I8:
4188 s390_cgdbr (code, ins->dreg, 5, ins->sreg1);
4189 break;
4190 case OP_FCONV_TO_U8:
4191 if (mono_hwcap_s390x_has_fpe) {
4192 s390_clgdbr (code, ins->dreg, 5, ins->sreg1, 0);
4193 } else {
4194 code = emit_double_to_int (cfg, code, ins->dreg, ins->sreg1, 8, FALSE);
4196 break;
4197 case OP_RCONV_TO_I1:
4198 s390_cgebr (code, ins->dreg, 5, ins->sreg1);
4199 s390_ltgr (code, ins->dreg, ins->dreg);
4200 s390_jnl (code, 4);
4201 s390_oill (code, ins->dreg, 0x80);
4202 s390_lghi (code, s390_r0, 0xff);
4203 s390_ngr (code, ins->dreg, s390_r0);
4204 break;
4205 case OP_RCONV_TO_U1:
4206 if (mono_hwcap_s390x_has_fpe) {
4207 s390_clgebr (code, ins->dreg, 5, ins->sreg1, 0);
4208 s390_lghi (code, s390_r0, 0xff);
4209 s390_ngr (code, ins->dreg, s390_r0);
4210 } else {
4211 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4213 break;
4214 case OP_RCONV_TO_I2:
4215 s390_cgebr (code, ins->dreg, 5, ins->sreg1);
4216 s390_ltgr (code, ins->dreg, ins->dreg);
4217 s390_jnl (code, 4);
4218 s390_oill (code, ins->dreg, 0x8000);
4219 s390_llill (code, s390_r0, 0xffff);
4220 s390_ngr (code, ins->dreg, s390_r0);
4221 break;
4222 case OP_RCONV_TO_U2:
4223 if (mono_hwcap_s390x_has_fpe) {
4224 s390_clgebr (code, ins->dreg, 5, ins->sreg1, 0);
4225 s390_llill (code, s390_r0, 0xffff);
4226 s390_ngr (code, ins->dreg, s390_r0);
4227 } else {
4228 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4230 break;
4231 case OP_RCONV_TO_I4:
4232 case OP_RCONV_TO_I:
4233 s390_cfebr (code, ins->dreg, 5, ins->sreg1);
4234 break;
4235 case OP_RCONV_TO_U4:
4236 if (mono_hwcap_s390x_has_fpe) {
4237 s390_clfebr (code, ins->dreg, 5, ins->sreg1, 0);
4238 } else {
4239 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4241 break;
4242 case OP_RCONV_TO_I8:
4243 s390_cgebr (code, ins->dreg, 5, ins->sreg1);
4244 break;
4245 case OP_RCONV_TO_U8:
4246 if (mono_hwcap_s390x_has_fpe) {
4247 s390_clgebr (code, ins->dreg, 5, ins->sreg1, 0);
4248 } else {
4249 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 8, FALSE);
4251 break;
4252 case OP_LCONV_TO_OVF_I: {
4253 /* Valid ints: 0xffffffff:8000000 to 00000000:0x7f000000 */
4254 short int *o[5];
4255 s390_ltgr (code, ins->sreg2, ins->sreg2);
4256 s390_jnl (code, 0); CODEPTR(code, o[0]);
4257 s390_ltgr (code, ins->sreg1, ins->sreg1);
4258 s390_jnl (code, 0); CODEPTR(code, o[1]);
4259 s390_lhi (code, s390_r13, -1);
4260 s390_cgr (code, ins->sreg1, s390_r13);
4261 s390_jnz (code, 0); CODEPTR(code, o[2]);
4262 if (ins->dreg != ins->sreg2)
4263 s390_lgr (code, ins->dreg, ins->sreg2);
4264 s390_j (code, 0); CODEPTR(code, o[3]);
4265 PTRSLOT(code, o[0]);
4266 s390_jz (code, 0); CODEPTR(code, o[4]);
4267 PTRSLOT(code, o[1]);
4268 PTRSLOT(code, o[2]);
4269 mono_add_patch_info (cfg, code - cfg->native_code,
4270 MONO_PATCH_INFO_EXC, "OverflowException");
4271 s390_brasl (code, s390_r14, 0);
4272 PTRSLOT(code, o[3]);
4273 PTRSLOT(code, o[4]);
4275 break;
4276 case OP_ABS: {
4277 s390_lpdbr (code, ins->dreg, ins->sreg1);
4279 break;
4280 case OP_SQRT: {
4281 s390_sqdbr (code, ins->dreg, ins->sreg1);
4283 break;
4284 case OP_FADD: {
4285 CHECK_SRCDST_COM_F;
4286 s390_adbr (code, ins->dreg, src2);
4288 break;
4289 case OP_RADD: {
4290 CHECK_SRCDST_COM_F;
4291 s390_aebr (code, ins->dreg, src2);
4293 break;
4294 case OP_FSUB: {
4295 CHECK_SRCDST_NCOM_F;
4296 s390_sdbr (code, ins->dreg, src2);
4298 break;
4299 case OP_RSUB: {
4300 CHECK_SRCDST_NCOM_F;
4301 s390_sebr (code, ins->dreg, src2);
4303 break;
4304 case OP_FMUL: {
4305 CHECK_SRCDST_COM_F;
4306 s390_mdbr (code, ins->dreg, src2);
4308 break;
4309 case OP_RMUL: {
4310 CHECK_SRCDST_COM_F;
4311 s390_meer (code, ins->dreg, src2);
4313 break;
4314 case OP_FDIV: {
4315 CHECK_SRCDST_NCOM_F;
4316 s390_ddbr (code, ins->dreg, src2);
4318 break;
4319 case OP_RDIV: {
4320 CHECK_SRCDST_NCOM_F;
4321 s390_debr (code, ins->dreg, src2);
4323 break;
4324 case OP_FNEG: {
4325 s390_lcdbr (code, ins->dreg, ins->sreg1);
4327 break;
4328 case OP_RNEG: {
4329 s390_lcebr (code, ins->dreg, ins->sreg1);
4331 break;
4332 case OP_FREM: {
4333 CHECK_SRCDST_NCOM_F;
4334 s390_didbr (code, ins->dreg, src2, 5, s390_f15);
4336 break;
4337 case OP_RREM: {
4338 CHECK_SRCDST_NCOM_F;
4339 s390_diebr (code, ins->dreg, src2, 5, s390_f15);
4341 break;
4342 case OP_FCOMPARE: {
4343 s390_cdbr (code, ins->sreg1, ins->sreg2);
4345 break;
4346 case OP_RCOMPARE: {
4347 s390_cebr (code, ins->sreg1, ins->sreg2);
4349 break;
4350 case OP_FCEQ: {
4351 s390_cdbr (code, ins->sreg1, ins->sreg2);
4352 s390_lghi (code, ins->dreg, 1);
4353 s390_je (code, 4);
4354 s390_lghi (code, ins->dreg, 0);
4356 break;
4357 case OP_FCLT: {
4358 s390_cdbr (code, ins->sreg1, ins->sreg2);
4359 s390_lghi (code, ins->dreg, 1);
4360 s390_jl (code, 4);
4361 s390_lghi (code, ins->dreg, 0);
4363 break;
4364 case OP_FCLT_UN: {
4365 s390_cdbr (code, ins->sreg1, ins->sreg2);
4366 s390_lghi (code, ins->dreg, 1);
4367 s390_jlo (code, 4);
4368 s390_lghi (code, ins->dreg, 0);
4370 break;
4371 case OP_FCGT: {
4372 s390_cdbr (code, ins->sreg1, ins->sreg2);
4373 s390_lghi (code, ins->dreg, 1);
4374 s390_jh (code, 4);
4375 s390_lghi (code, ins->dreg, 0);
4377 break;
4378 case OP_FCGT_UN: {
4379 s390_cdbr (code, ins->sreg1, ins->sreg2);
4380 s390_lghi (code, ins->dreg, 1);
4381 s390_jho (code, 4);
4382 s390_lghi (code, ins->dreg, 0);
4384 break;
4385 case OP_FCNEQ: {
4386 s390_cdbr (code, ins->sreg1, ins->sreg2);
4387 s390_lghi (code, ins->dreg, 1);
4388 s390_jne (code, 4);
4389 s390_lghi (code, ins->dreg, 0);
4391 break;
4392 case OP_FCGE: {
4393 s390_cdbr (code, ins->sreg1, ins->sreg2);
4394 s390_lghi (code, ins->dreg, 1);
4395 s390_jhe (code, 4);
4396 s390_lghi (code, ins->dreg, 0);
4398 break;
4399 case OP_FCLE: {
4400 s390_cdbr (code, ins->sreg1, ins->sreg2);
4401 s390_lghi (code, ins->dreg, 1);
4402 s390_jle (code, 4);
4403 s390_lghi (code, ins->dreg, 0);
4405 break;
4406 case OP_RCEQ: {
4407 s390_cdbr (code, ins->sreg1, ins->sreg2);
4408 s390_lghi (code, ins->dreg, 1);
4409 s390_je (code, 4);
4410 s390_lghi (code, ins->dreg, 0);
4412 break;
4413 case OP_RCLT: {
4414 s390_cdbr (code, ins->sreg1, ins->sreg2);
4415 s390_lghi (code, ins->dreg, 1);
4416 s390_jl (code, 4);
4417 s390_lghi (code, ins->dreg, 0);
4419 break;
4420 case OP_RCLT_UN: {
4421 s390_cdbr (code, ins->sreg1, ins->sreg2);
4422 s390_lghi (code, ins->dreg, 1);
4423 s390_jlo (code, 4);
4424 s390_lghi (code, ins->dreg, 0);
4426 break;
4427 case OP_RCGT: {
4428 s390_cdbr (code, ins->sreg1, ins->sreg2);
4429 s390_lghi (code, ins->dreg, 1);
4430 s390_jh (code, 4);
4431 s390_lghi (code, ins->dreg, 0);
4433 break;
4434 case OP_RCGT_UN: {
4435 s390_cdbr (code, ins->sreg1, ins->sreg2);
4436 s390_lghi (code, ins->dreg, 1);
4437 s390_jho (code, 4);
4438 s390_lghi (code, ins->dreg, 0);
4440 break;
4441 case OP_RCNEQ: {
4442 s390_cdbr (code, ins->sreg1, ins->sreg2);
4443 s390_lghi (code, ins->dreg, 1);
4444 s390_jne (code, 4);
4445 s390_lghi (code, ins->dreg, 0);
4447 break;
4448 case OP_RCGE: {
4449 s390_cdbr (code, ins->sreg1, ins->sreg2);
4450 s390_lghi (code, ins->dreg, 1);
4451 s390_jhe (code, 4);
4452 s390_lghi (code, ins->dreg, 0);
4454 break;
4455 case OP_RCLE: {
4456 s390_cebr (code, ins->sreg1, ins->sreg2);
4457 s390_lghi (code, ins->dreg, 1);
4458 s390_jle (code, 4);
4459 s390_lghi (code, ins->dreg, 0);
4461 break;
4462 case OP_FBEQ: {
4463 short *o;
4464 s390_jo (code, 0); CODEPTR(code, o);
4465 EMIT_COND_BRANCH (ins, S390_CC_EQ);
4466 PTRSLOT (code, o);
4468 break;
4469 case OP_FBNE_UN:
4470 EMIT_COND_BRANCH (ins, S390_CC_NE|S390_CC_OV);
4471 break;
4472 case OP_FBLT: {
4473 short *o;
4474 s390_jo (code, 0); CODEPTR(code, o);
4475 EMIT_COND_BRANCH (ins, S390_CC_LT);
4476 PTRSLOT (code, o);
4478 break;
4479 case OP_FBLT_UN:
4480 EMIT_COND_BRANCH (ins, S390_CC_LT|S390_CC_OV);
4481 break;
4482 case OP_FBGT: {
4483 short *o;
4484 s390_jo (code, 0); CODEPTR(code, o);
4485 EMIT_COND_BRANCH (ins, S390_CC_GT);
4486 PTRSLOT (code, o);
4488 break;
4489 case OP_FBGT_UN:
4490 EMIT_COND_BRANCH (ins, S390_CC_GT|S390_CC_OV);
4491 break;
4492 case OP_FBGE: {
4493 short *o;
4494 s390_jo (code, 0); CODEPTR(code, o);
4495 EMIT_COND_BRANCH (ins, S390_CC_GE);
4496 PTRSLOT (code, o);
4498 break;
4499 case OP_FBGE_UN:
4500 EMIT_COND_BRANCH (ins, S390_CC_GE|S390_CC_OV);
4501 break;
4502 case OP_FBLE: {
4503 short *o;
4504 s390_jo (code, 0); CODEPTR(code, o);
4505 EMIT_COND_BRANCH (ins, S390_CC_LE);
4506 PTRSLOT (code, o);
4508 break;
4509 case OP_FBLE_UN:
4510 EMIT_COND_BRANCH (ins, S390_CC_LE|S390_CC_OV);
4511 break;
4512 case OP_CKFINITE: {
4513 short *o;
4514 s390_lhi (code, s390_r13, 0x7f);
4515 s390_tcdb (code, ins->sreg1, 0, s390_r13, 0);
4516 s390_jz (code, 0); CODEPTR(code, o);
4517 mono_add_patch_info (cfg, code - cfg->native_code,
4518 MONO_PATCH_INFO_EXC, "OverflowException");
4519 s390_brasl (code, s390_r14,0);
4520 PTRSLOT(code, o);
4522 break;
4523 case OP_S390_MOVE: {
4524 if (ins->backend.size > 0) {
4525 if (ins->backend.size <= 256) {
4526 s390_mvc (code, ins->backend.size, ins->dreg,
4527 ins->inst_offset, ins->sreg1, ins->inst_imm);
4528 } else {
4529 s390_lgr (code, s390_r0, ins->dreg);
4530 if (ins->inst_offset > 0) {
4531 if (s390_is_imm16 (ins->inst_offset)) {
4532 s390_aghi (code, s390_r0, ins->inst_offset);
4533 } else if (s390_is_imm32 (ins->inst_offset)) {
4534 s390_agfi (code, s390_r0, ins->inst_offset);
4535 } else {
4536 S390_SET (code, s390_r13, ins->inst_offset);
4537 s390_agr (code, s390_r0, s390_r13);
4540 s390_lgr (code, s390_r12, ins->sreg1);
4541 if (ins->inst_imm > 0) {
4542 if (s390_is_imm16 (ins->inst_imm)) {
4543 s390_aghi (code, s390_r12, ins->inst_imm);
4544 } else if (s390_is_imm32 (ins->inst_imm)) {
4545 s390_agfi (code, s390_r12, ins->inst_imm);
4546 } else {
4547 S390_SET (code, s390_r13, ins->inst_imm);
4548 s390_agr (code, s390_r12, s390_r13);
4551 if (s390_is_imm16 (ins->backend.size)) {
4552 s390_lghi (code, s390_r1, ins->backend.size);
4553 } else if (s390_is_imm32 (ins->inst_offset)) {
4554 s390_agfi (code, s390_r1, ins->backend.size);
4555 } else {
4556 S390_SET (code, s390_r13, ins->backend.size);
4557 s390_agr (code, s390_r1, s390_r13);
4559 s390_lgr (code, s390_r13, s390_r1);
4560 s390_mvcle(code, s390_r0, s390_r12, 0, 0);
4561 s390_jo (code, -2);
4565 break;
4566 case OP_ATOMIC_ADD_I8: {
4567 if (mono_hwcap_s390x_has_ia) {
4568 s390_laag (code, ins->dreg, ins->sreg2, ins->inst_basereg, ins->inst_offset);
4569 s390_agr (code, ins->dreg, ins->sreg2);
4570 } else {
4571 s390_lgr (code, s390_r1, ins->sreg2);
4572 s390_lg (code, s390_r0, 0, ins->inst_basereg, ins->inst_offset);
4573 s390_agr (code, s390_r1, s390_r0);
4574 s390_csg (code, s390_r0, s390_r1, ins->inst_basereg, ins->inst_offset);
4575 s390_jnz (code, -10);
4576 s390_lgr (code, ins->dreg, s390_r1);
4579 break;
4580 case OP_ATOMIC_EXCHANGE_I8: {
4581 s390_lg (code, s390_r0, 0, ins->inst_basereg, ins->inst_offset);
4582 s390_csg (code, s390_r0, ins->sreg2, ins->inst_basereg, ins->inst_offset);
4583 s390_jnz (code, -6);
4584 s390_lgr (code, ins->dreg, s390_r0);
4586 break;
4587 case OP_ATOMIC_ADD_I4: {
4588 if (mono_hwcap_s390x_has_ia) {
4589 s390_laa (code, ins->dreg, ins->sreg2, ins->inst_basereg, ins->inst_offset);
4590 s390_ar (code, ins->dreg, ins->sreg2);
4591 } else {
4592 s390_lgfr(code, s390_r1, ins->sreg2);
4593 s390_lgf (code, s390_r0, 0, ins->inst_basereg, ins->inst_offset);
4594 s390_agr (code, s390_r1, s390_r0);
4595 s390_cs (code, s390_r0, s390_r1, ins->inst_basereg, ins->inst_offset);
4596 s390_jnz (code, -9);
4597 s390_lgfr(code, ins->dreg, s390_r1);
4600 break;
4601 case OP_ATOMIC_EXCHANGE_I4: {
4602 s390_l (code, s390_r0, 0, ins->inst_basereg, ins->inst_offset);
4603 s390_cs (code, s390_r0, ins->sreg2, ins->inst_basereg, ins->inst_offset);
4604 s390_jnz (code, -4);
4605 s390_lgfr(code, ins->dreg, s390_r0);
4607 break;
4608 case OP_S390_BKCHAIN: {
4609 s390_lgr (code, ins->dreg, ins->sreg1);
4610 if (s390_is_imm16 (cfg->stack_offset)) {
4611 s390_aghi (code, ins->dreg, cfg->stack_offset);
4612 } else if (s390_is_imm32 (cfg->stack_offset)) {
4613 s390_agfi (code, ins->dreg, cfg->stack_offset);
4614 } else {
4615 S390_SET (code, s390_r13, cfg->stack_offset);
4616 s390_agr (code, ins->dreg, s390_r13);
4619 break;
4620 case OP_MEMORY_BARRIER:
4621 s390_mem (code);
4622 break;
4623 case OP_LIVERANGE_START: {
4624 if (cfg->verbose_level > 1)
4625 printf ("R%d START=0x%x\n", MONO_VARINFO (cfg, ins->inst_c0)->vreg, (int)(code - cfg->native_code));
4626 MONO_VARINFO (cfg, ins->inst_c0)->live_range_start = code - cfg->native_code;
4627 break;
4629 case OP_LIVERANGE_END: {
4630 if (cfg->verbose_level > 1)
4631 printf ("R%d END=0x%x\n", MONO_VARINFO (cfg, ins->inst_c0)->vreg, (int)(code - cfg->native_code));
4632 MONO_VARINFO (cfg, ins->inst_c0)->live_range_end = code - cfg->native_code;
4633 break;
4635 case OP_GC_SAFE_POINT: {
4636 short *br;
4638 s390_ltg (code, s390_r0, 0, ins->sreg1, 0);
4639 s390_jz (code, 0); CODEPTR(code, br);
4640 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_ABS,
4641 mono_threads_state_poll);
4642 S390_CALL_TEMPLATE (code, s390_r14);
4643 PTRSLOT (code, br);
4644 break;
4646 case OP_GC_LIVENESS_DEF:
4647 case OP_GC_LIVENESS_USE:
4648 case OP_GC_PARAM_SLOT_LIVENESS_DEF:
4649 ins->backend.pc_offset = code - cfg->native_code;
4650 break;
4651 case OP_GC_SPILL_SLOT_LIVENESS_DEF:
4652 ins->backend.pc_offset = code - cfg->native_code;
4653 bb->spill_slot_defs = g_slist_prepend_mempool (cfg->mempool, bb->spill_slot_defs, ins);
4654 break;
4655 #ifdef MONO_ARCH_SIMD_INTRINSICS
4656 case OP_ADDPS:
4657 s390x_addps (code, ins->sreg1, ins->sreg2);
4658 break;
4659 case OP_DIVPS:
4660 s390x_divps (code, ins->sreg1, ins->sreg2);
4661 break;
4662 case OP_MULPS:
4663 s390x_mulps (code, ins->sreg1, ins->sreg2);
4664 break;
4665 case OP_SUBPS:
4666 s390x_subps (code, ins->sreg1, ins->sreg2);
4667 break;
4668 case OP_MAXPS:
4669 s390x_maxps (code, ins->sreg1, ins->sreg2);
4670 break;
4671 case OP_MINPS:
4672 s390x_minps (code, ins->sreg1, ins->sreg2);
4673 break;
4674 case OP_COMPPS:
4675 g_assert (ins->inst_c0 >= 0 && ins->inst_c0 <= 7);
4676 s390x_cmpps_imm (code, ins->sreg1, ins->sreg2, ins->inst_c0);
4677 break;
4678 case OP_ANDPS:
4679 s390x_andps (code, ins->sreg1, ins->sreg2);
4680 break;
4681 case OP_ANDNPS:
4682 s390x_andnps (code, ins->sreg1, ins->sreg2);
4683 break;
4684 case OP_ORPS:
4685 s390x_orps (code, ins->sreg1, ins->sreg2);
4686 break;
4687 case OP_XORPS:
4688 s390x_xorps (code, ins->sreg1, ins->sreg2);
4689 break;
4690 case OP_SQRTPS:
4691 s390x_sqrtps (code, ins->dreg, ins->sreg1);
4692 break;
4693 case OP_RSQRTPS:
4694 s390x_rsqrtps (code, ins->dreg, ins->sreg1);
4695 break;
4696 case OP_RCPPS:
4697 s390x_rcpps (code, ins->dreg, ins->sreg1);
4698 break;
4699 case OP_ADDSUBPS:
4700 s390x_addsubps (code, ins->sreg1, ins->sreg2);
4701 break;
4702 case OP_HADDPS:
4703 s390x_haddps (code, ins->sreg1, ins->sreg2);
4704 break;
4705 case OP_HSUBPS:
4706 s390x_hsubps (code, ins->sreg1, ins->sreg2);
4707 break;
4708 case OP_DUPPS_HIGH:
4709 s390x_movshdup (code, ins->dreg, ins->sreg1);
4710 break;
4711 case OP_DUPPS_LOW:
4712 s390x_movsldup (code, ins->dreg, ins->sreg1);
4713 break;
4715 case OP_PSHUFLEW_HIGH:
4716 g_assert (ins->inst_c0 >= 0 && ins->inst_c0 <= 0xFF);
4717 s390x_pshufhw_imm (code, ins->dreg, ins->sreg1, ins->inst_c0);
4718 break;
4719 case OP_PSHUFLEW_LOW:
4720 g_assert (ins->inst_c0 >= 0 && ins->inst_c0 <= 0xFF);
4721 s390x_pshuflw_imm (code, ins->dreg, ins->sreg1, ins->inst_c0);
4722 break;
4723 case OP_PSHUFLED:
4724 g_assert (ins->inst_c0 >= 0 && ins->inst_c0 <= 0xFF);
4725 s390x_pshufd_imm (code, ins->dreg, ins->sreg1, ins->inst_c0);
4726 break;
4727 case OP_SHUFPS:
4728 g_assert (ins->inst_c0 >= 0 && ins->inst_c0 <= 0xFF);
4729 s390x_shufps_imm (code, ins->sreg1, ins->sreg2, ins->inst_c0);
4730 break;
4731 case OP_SHUFPD:
4732 g_assert (ins->inst_c0 >= 0 && ins->inst_c0 <= 0x3);
4733 s390x_shufpd_imm (code, ins->sreg1, ins->sreg2, ins->inst_c0);
4734 break;
4736 case OP_ADDPD:
4737 s390x_addpd (code, ins->sreg1, ins->sreg2);
4738 break;
4739 case OP_DIVPD:
4740 s390x_divpd (code, ins->sreg1, ins->sreg2);
4741 break;
4742 case OP_MULPD:
4743 s390x_mulpd (code, ins->sreg1, ins->sreg2);
4744 break;
4745 case OP_SUBPD:
4746 s390x_subpd (code, ins->sreg1, ins->sreg2);
4747 break;
4748 case OP_MAXPD:
4749 s390x_maxpd (code, ins->sreg1, ins->sreg2);
4750 break;
4751 case OP_MINPD:
4752 s390x_minpd (code, ins->sreg1, ins->sreg2);
4753 break;
4754 case OP_COMPPD:
4755 g_assert (ins->inst_c0 >= 0 && ins->inst_c0 <= 7);
4756 s390x_cmppd_imm (code, ins->sreg1, ins->sreg2, ins->inst_c0);
4757 break;
4758 case OP_ANDPD:
4759 s390x_andpd (code, ins->sreg1, ins->sreg2);
4760 break;
4761 case OP_ANDNPD:
4762 s390x_andnpd (code, ins->sreg1, ins->sreg2);
4763 break;
4764 case OP_ORPD:
4765 s390x_orpd (code, ins->sreg1, ins->sreg2);
4766 break;
4767 case OP_XORPD:
4768 s390x_xorpd (code, ins->sreg1, ins->sreg2);
4769 break;
4770 case OP_SQRTPD:
4771 s390x_sqrtpd (code, ins->dreg, ins->sreg1);
4772 break;
4773 case OP_ADDSUBPD:
4774 s390x_addsubpd (code, ins->sreg1, ins->sreg2);
4775 break;
4776 case OP_HADDPD:
4777 s390x_haddpd (code, ins->sreg1, ins->sreg2);
4778 break;
4779 case OP_HSUBPD:
4780 s390x_hsubpd (code, ins->sreg1, ins->sreg2);
4781 break;
4782 case OP_DUPPD:
4783 s390x_movddup (code, ins->dreg, ins->sreg1);
4784 break;
4786 case OP_EXTRACT_MASK:
4787 s390x_pmovmskb (code, ins->dreg, ins->sreg1);
4788 break;
4790 case OP_PAND:
4791 s390x_pand (code, ins->sreg1, ins->sreg2);
4792 break;
4793 case OP_POR:
4794 s390x_por (code, ins->sreg1, ins->sreg2);
4795 break;
4796 case OP_PXOR:
4797 s390x_pxor (code, ins->sreg1, ins->sreg2);
4798 break;
4800 case OP_PADDB:
4801 s390x_paddb (code, ins->sreg1, ins->sreg2);
4802 break;
4803 case OP_PADDW:
4804 s390x_paddw (code, ins->sreg1, ins->sreg2);
4805 break;
4806 case OP_PADDD:
4807 s390x_paddd (code, ins->sreg1, ins->sreg2);
4808 break;
4809 case OP_PADDQ:
4810 s390x_paddq (code, ins->sreg1, ins->sreg2);
4811 break;
4813 case OP_PSUBB:
4814 s390x_psubb (code, ins->sreg1, ins->sreg2);
4815 break;
4816 case OP_PSUBW:
4817 s390x_psubw (code, ins->sreg1, ins->sreg2);
4818 break;
4819 case OP_PSUBD:
4820 s390x_psubd (code, ins->sreg1, ins->sreg2);
4821 break;
4822 case OP_PSUBQ:
4823 s390x_psubq (code, ins->sreg1, ins->sreg2);
4824 break;
4826 case OP_PMAXB_UN:
4827 s390x_pmaxub (code, ins->sreg1, ins->sreg2);
4828 break;
4829 case OP_PMAXW_UN:
4830 s390x_pmaxuw (code, ins->sreg1, ins->sreg2);
4831 break;
4832 case OP_PMAXD_UN:
4833 s390x_pmaxud (code, ins->sreg1, ins->sreg2);
4834 break;
4836 case OP_PMAXB:
4837 s390x_pmaxsb (code, ins->sreg1, ins->sreg2);
4838 break;
4839 case OP_PMAXW:
4840 s390x_pmaxsw (code, ins->sreg1, ins->sreg2);
4841 break;
4842 case OP_PMAXD:
4843 s390x_pmaxsd (code, ins->sreg1, ins->sreg2);
4844 break;
4846 case OP_PAVGB_UN:
4847 s390x_pavgb (code, ins->sreg1, ins->sreg2);
4848 break;
4849 case OP_PAVGW_UN:
4850 s390x_pavgw (code, ins->sreg1, ins->sreg2);
4851 break;
4853 case OP_PMINB_UN:
4854 s390x_pminub (code, ins->sreg1, ins->sreg2);
4855 break;
4856 case OP_PMINW_UN:
4857 s390x_pminuw (code, ins->sreg1, ins->sreg2);
4858 break;
4859 case OP_PMIND_UN:
4860 s390x_pminud (code, ins->sreg1, ins->sreg2);
4861 break;
4863 case OP_PMINB:
4864 s390x_pminsb (code, ins->sreg1, ins->sreg2);
4865 break;
4866 case OP_PMINW:
4867 s390x_pminsw (code, ins->sreg1, ins->sreg2);
4868 break;
4869 case OP_PMIND:
4870 s390x_pminsd (code, ins->sreg1, ins->sreg2);
4871 break;
4873 case OP_PCMPEQB:
4874 s390x_pcmpeqb (code, ins->sreg1, ins->sreg2);
4875 break;
4876 case OP_PCMPEQW:
4877 s390x_pcmpeqw (code, ins->sreg1, ins->sreg2);
4878 break;
4879 case OP_PCMPEQD:
4880 s390x_pcmpeqd (code, ins->sreg1, ins->sreg2);
4881 break;
4882 case OP_PCMPEQQ:
4883 s390x_pcmpeqq (code, ins->sreg1, ins->sreg2);
4884 break;
4886 case OP_PCMPGTB:
4887 s390x_pcmpgtb (code, ins->sreg1, ins->sreg2);
4888 break;
4889 case OP_PCMPGTW:
4890 s390x_pcmpgtw (code, ins->sreg1, ins->sreg2);
4891 break;
4892 case OP_PCMPGTD:
4893 s390x_pcmpgtd (code, ins->sreg1, ins->sreg2);
4894 break;
4895 case OP_PCMPGTQ:
4896 s390x_pcmpgtq (code, ins->sreg1, ins->sreg2);
4897 break;
4899 case OP_PSUM_ABS_DIFF:
4900 s390x_psadbw (code, ins->sreg1, ins->sreg2);
4901 break;
4903 case OP_UNPACK_LOWB:
4904 s390x_punpcklbw (code, ins->sreg1, ins->sreg2);
4905 break;
4906 case OP_UNPACK_LOWW:
4907 s390x_punpcklwd (code, ins->sreg1, ins->sreg2);
4908 break;
4909 case OP_UNPACK_LOWD:
4910 s390x_punpckldq (code, ins->sreg1, ins->sreg2);
4911 break;
4912 case OP_UNPACK_LOWQ:
4913 s390x_punpcklqdq (code, ins->sreg1, ins->sreg2);
4914 break;
4915 case OP_UNPACK_LOWPS:
4916 s390x_unpcklps (code, ins->sreg1, ins->sreg2);
4917 break;
4918 case OP_UNPACK_LOWPD:
4919 s390x_unpcklpd (code, ins->sreg1, ins->sreg2);
4920 break;
4922 case OP_UNPACK_HIGHB:
4923 s390x_punpckhbw (code, ins->sreg1, ins->sreg2);
4924 break;
4925 case OP_UNPACK_HIGHW:
4926 s390x_punpckhwd (code, ins->sreg1, ins->sreg2);
4927 break;
4928 case OP_UNPACK_HIGHD:
4929 s390x_punpckhdq (code, ins->sreg1, ins->sreg2);
4930 break;
4931 case OP_UNPACK_HIGHQ:
4932 s390x_punpckhqdq (code, ins->sreg1, ins->sreg2);
4933 break;
4934 case OP_UNPACK_HIGHPS:
4935 s390x_unpckhps (code, ins->sreg1, ins->sreg2);
4936 break;
4937 case OP_UNPACK_HIGHPD:
4938 s390x_unpckhpd (code, ins->sreg1, ins->sreg2);
4939 break;
4941 case OP_PACKW:
4942 s390x_packsswb (code, ins->sreg1, ins->sreg2);
4943 break;
4944 case OP_PACKD:
4945 s390x_packssdw (code, ins->sreg1, ins->sreg2);
4946 break;
4947 case OP_PACKW_UN:
4948 s390x_packuswb (code, ins->sreg1, ins->sreg2);
4949 break;
4950 case OP_PACKD_UN:
4951 s390x_packusdw (code, ins->sreg1, ins->sreg2);
4952 break;
4954 case OP_PADDB_SAT_UN:
4955 s390x_paddusb (code, ins->sreg1, ins->sreg2);
4956 break;
4957 case OP_PSUBB_SAT_UN:
4958 s390x_psubusb (code, ins->sreg1, ins->sreg2);
4959 break;
4960 case OP_PADDW_SAT_UN:
4961 s390x_paddusw (code, ins->sreg1, ins->sreg2);
4962 break;
4963 case OP_PSUBW_SAT_UN:
4964 s390x_psubusw (code, ins->sreg1, ins->sreg2);
4965 break;
4967 case OP_PADDB_SAT:
4968 s390x_paddsb (code, ins->sreg1, ins->sreg2);
4969 break;
4970 case OP_PSUBB_SAT:
4971 s390x_psubsb (code, ins->sreg1, ins->sreg2);
4972 break;
4973 case OP_PADDW_SAT:
4974 s390x_paddsw (code, ins->sreg1, ins->sreg2);
4975 break;
4976 case OP_PSUBW_SAT:
4977 s390x_psubsw (code, ins->sreg1, ins->sreg2);
4978 break;
4980 case OP_PMULW:
4981 s390x_pmullw (code, ins->sreg1, ins->sreg2);
4982 break;
4983 case OP_PMULD:
4984 s390x_pmulld (code, ins->sreg1, ins->sreg2);
4985 break;
4986 case OP_PMULQ:
4987 s390x_pmuludq (code, ins->sreg1, ins->sreg2);
4988 break;
4989 case OP_PMULW_HIGH_UN:
4990 s390x_pmulhuw (code, ins->sreg1, ins->sreg2);
4991 break;
4992 case OP_PMULW_HIGH:
4993 s390x_pmulhw (code, ins->sreg1, ins->sreg2);
4994 break;
4996 case OP_PSHRW:
4997 s390x_psrlw_reg_imm (code, ins->dreg, ins->inst_imm);
4998 break;
4999 case OP_PSHRW_REG:
5000 s390x_psrlw (code, ins->dreg, ins->sreg2);
5001 break;
5003 case OP_PSARW:
5004 s390x_psraw_reg_imm (code, ins->dreg, ins->inst_imm);
5005 break;
5006 case OP_PSARW_REG:
5007 s390x_psraw (code, ins->dreg, ins->sreg2);
5008 break;
5010 case OP_PSHLW:
5011 s390x_psllw_reg_imm (code, ins->dreg, ins->inst_imm);
5012 break;
5013 case OP_PSHLW_REG:
5014 s390x_psllw (code, ins->dreg, ins->sreg2);
5015 break;
5017 case OP_PSHRD:
5018 s390x_psrld_reg_imm (code, ins->dreg, ins->inst_imm);
5019 break;
5020 case OP_PSHRD_REG:
5021 s390x_psrld (code, ins->dreg, ins->sreg2);
5022 break;
5024 case OP_PSARD:
5025 s390x_psrad_reg_imm (code, ins->dreg, ins->inst_imm);
5026 break;
5027 case OP_PSARD_REG:
5028 s390x_psrad (code, ins->dreg, ins->sreg2);
5029 break;
5031 case OP_PSHLD:
5032 s390x_pslld_reg_imm (code, ins->dreg, ins->inst_imm);
5033 break;
5034 case OP_PSHLD_REG:
5035 s390x_pslld (code, ins->dreg, ins->sreg2);
5036 break;
5038 case OP_PSHRQ:
5039 s390x_psrlq_reg_imm (code, ins->dreg, ins->inst_imm);
5040 break;
5041 case OP_PSHRQ_REG:
5042 s390x_psrlq (code, ins->dreg, ins->sreg2);
5043 break;
5045 /*TODO: This is appart of the sse spec but not added
5046 case OP_PSARQ:
5047 s390x_psraq_reg_imm (code, ins->dreg, ins->inst_imm);
5048 break;
5049 case OP_PSARQ_REG:
5050 s390x_psraq (code, ins->dreg, ins->sreg2);
5051 break;
5054 case OP_PSHLQ:
5055 s390x_psllq_reg_imm (code, ins->dreg, ins->inst_imm);
5056 break;
5057 case OP_PSHLQ_REG:
5058 s390x_psllq (code, ins->dreg, ins->sreg2);
5059 break;
5060 case OP_CVTDQ2PD:
5061 s390x_cvtdq2pd (code, ins->dreg, ins->sreg1);
5062 break;
5063 case OP_CVTDQ2PS:
5064 s390x_cvtdq2ps (code, ins->dreg, ins->sreg1);
5065 break;
5066 case OP_CVTPD2DQ:
5067 s390x_cvtpd2dq (code, ins->dreg, ins->sreg1);
5068 break;
5069 case OP_CVTPD2PS:
5070 s390x_cvtpd2ps (code, ins->dreg, ins->sreg1);
5071 break;
5072 case OP_CVTPS2DQ:
5073 s390x_cvtps2dq (code, ins->dreg, ins->sreg1);
5074 break;
5075 case OP_CVTPS2PD:
5076 s390x_cvtps2pd (code, ins->dreg, ins->sreg1);
5077 break;
5078 case OP_CVTTPD2DQ:
5079 s390x_cvttpd2dq (code, ins->dreg, ins->sreg1);
5080 break;
5081 case OP_CVTTPS2DQ:
5082 s390x_cvttps2dq (code, ins->dreg, ins->sreg1);
5083 break;
5085 case OP_ICONV_TO_X:
5086 amd64_movd_xreg_reg_size (code, ins->dreg, ins->sreg1, 4);
5087 break;
5088 case OP_EXTRACT_I4:
5089 amd64_movd_reg_xreg_size (code, ins->dreg, ins->sreg1, 4);
5090 break;
5091 case OP_EXTRACT_I8:
5092 if (ins->inst_c0) {
5093 amd64_movhlps (code, MONO_ARCH_FP_SCRATCH_REG, ins->sreg1);
5094 amd64_movd_reg_xreg_size (code, ins->dreg, MONO_ARCH_FP_SCRATCH_REG, 8);
5095 } else {
5096 amd64_movd_reg_xreg_size (code, ins->dreg, ins->sreg1, 8);
5098 break;
5099 case OP_EXTRACT_I1:
5100 case OP_EXTRACT_U1:
5101 amd64_movd_reg_xreg_size (code, ins->dreg, ins->sreg1, 4);
5102 if (ins->inst_c0)
5103 amd64_shift_reg_imm (code, X86_SHR, ins->dreg, ins->inst_c0 * 8);
5104 amd64_widen_reg (code, ins->dreg, ins->dreg, ins->opcode == OP_EXTRACT_I1, FALSE);
5105 break;
5106 case OP_EXTRACT_I2:
5107 case OP_EXTRACT_U2:
5108 /*amd64_movd_reg_xreg_size (code, ins->dreg, ins->sreg1, 4);
5109 if (ins->inst_c0)
5110 amd64_shift_reg_imm_size (code, X86_SHR, ins->dreg, 16, 4);*/
5111 s390x_pextrw_imm (code, ins->dreg, ins->sreg1, ins->inst_c0);
5112 amd64_widen_reg_size (code, ins->dreg, ins->dreg, ins->opcode == OP_EXTRACT_I2, TRUE, 4);
5113 break;
5114 case OP_EXTRACT_R8:
5115 if (ins->inst_c0)
5116 amd64_movhlps (code, ins->dreg, ins->sreg1);
5117 else
5118 s390x_movsd (code, ins->dreg, ins->sreg1);
5119 break;
5120 case OP_INSERT_I2:
5121 s390x_pinsrw_imm (code, ins->sreg1, ins->sreg2, ins->inst_c0);
5122 break;
5123 case OP_EXTRACTX_U2:
5124 s390x_pextrw_imm (code, ins->dreg, ins->sreg1, ins->inst_c0);
5125 break;
5126 case OP_INSERTX_U1_SLOW:
5127 /*sreg1 is the extracted ireg (scratch)
5128 /sreg2 is the to be inserted ireg (scratch)
5129 /dreg is the xreg to receive the value*/
5131 /*clear the bits from the extracted word*/
5132 amd64_alu_reg_imm (code, X86_AND, ins->sreg1, ins->inst_c0 & 1 ? 0x00FF : 0xFF00);
5133 /*shift the value to insert if needed*/
5134 if (ins->inst_c0 & 1)
5135 amd64_shift_reg_imm_size (code, X86_SHL, ins->sreg2, 8, 4);
5136 /*join them together*/
5137 amd64_alu (code, X86_OR, ins->sreg1, ins->sreg2);
5138 s390x_pinsrw_imm (code, ins->dreg, ins->sreg1, ins->inst_c0 / 2);
5139 break;
5140 case OP_INSERTX_I4_SLOW:
5141 s390x_pinsrw_imm (code, ins->dreg, ins->sreg2, ins->inst_c0 * 2);
5142 amd64_shift_reg_imm (code, X86_SHR, ins->sreg2, 16);
5143 s390x_pinsrw_imm (code, ins->dreg, ins->sreg2, ins->inst_c0 * 2 + 1);
5144 break;
5145 case OP_INSERTX_I8_SLOW:
5146 amd64_movd_xreg_reg_size(code, MONO_ARCH_FP_SCRATCH_REG, ins->sreg2, 8);
5147 if (ins->inst_c0)
5148 amd64_movlhps (code, ins->dreg, MONO_ARCH_FP_SCRATCH_REG);
5149 else
5150 s390x_movsd (code, ins->dreg, MONO_ARCH_FP_SCRATCH_REG);
5151 break;
5153 case OP_INSERTX_R4_SLOW:
5154 switch (ins->inst_c0) {
5155 case 0:
5156 if (cfg->r4fp)
5157 s390x_movss (code, ins->dreg, ins->sreg2);
5158 else
5159 s390x_cvtsd2ss (code, ins->dreg, ins->sreg2);
5160 break;
5161 case 1:
5162 s390x_pshufd_imm (code, ins->dreg, ins->dreg, mono_simd_shuffle_mask(1, 0, 2, 3));
5163 if (cfg->r4fp)
5164 s390x_movss (code, ins->dreg, ins->sreg2);
5165 else
5166 s390x_cvtsd2ss (code, ins->dreg, ins->sreg2);
5167 s390x_pshufd_imm (code, ins->dreg, ins->dreg, mono_simd_shuffle_mask(1, 0, 2, 3));
5168 break;
5169 case 2:
5170 s390x_pshufd_imm (code, ins->dreg, ins->dreg, mono_simd_shuffle_mask(2, 1, 0, 3));
5171 if (cfg->r4fp)
5172 s390x_movss (code, ins->dreg, ins->sreg2);
5173 else
5174 s390x_cvtsd2ss (code, ins->dreg, ins->sreg2);
5175 s390x_pshufd_imm (code, ins->dreg, ins->dreg, mono_simd_shuffle_mask(2, 1, 0, 3));
5176 break;
5177 case 3:
5178 s390x_pshufd_imm (code, ins->dreg, ins->dreg, mono_simd_shuffle_mask(3, 1, 2, 0));
5179 if (cfg->r4fp)
5180 s390x_movss (code, ins->dreg, ins->sreg2);
5181 else
5182 s390x_cvtsd2ss (code, ins->dreg, ins->sreg2);
5183 s390x_pshufd_imm (code, ins->dreg, ins->dreg, mono_simd_shuffle_mask(3, 1, 2, 0));
5184 break;
5186 break;
5187 case OP_INSERTX_R8_SLOW:
5188 if (ins->inst_c0)
5189 amd64_movlhps (code, ins->dreg, ins->sreg2);
5190 else
5191 s390x_movsd (code, ins->dreg, ins->sreg2);
5192 break;
5193 case OP_STOREX_MEMBASE_REG:
5194 case OP_STOREX_MEMBASE:
5195 s390x_movups_membase_reg (code, ins->dreg, ins->inst_offset, ins->sreg1);
5196 break;
5197 case OP_LOADX_MEMBASE:
5198 s390x_movups_reg_membase (code, ins->dreg, ins->sreg1, ins->inst_offset);
5199 break;
5200 case OP_LOADX_ALIGNED_MEMBASE:
5201 s390x_movaps_reg_membase (code, ins->dreg, ins->sreg1, ins->inst_offset);
5202 break;
5203 case OP_STOREX_ALIGNED_MEMBASE_REG:
5204 s390x_movaps_membase_reg (code, ins->dreg, ins->inst_offset, ins->sreg1);
5205 break;
5206 case OP_STOREX_NTA_MEMBASE_REG:
5207 s390x_movntps_reg_membase (code, ins->dreg, ins->sreg1, ins->inst_offset);
5208 break;
5209 case OP_PREFETCH_MEMBASE:
5210 s390x_prefetch_reg_membase (code, ins->backend.arg_info, ins->sreg1, ins->inst_offset);
5211 break;
5213 case OP_XMOVE:
5214 /*FIXME the peephole pass should have killed this*/
5215 if (ins->dreg != ins->sreg1)
5216 s390x_movaps (code, ins->dreg, ins->sreg1);
5217 break;
5218 case OP_XZERO:
5219 s390x_pxor (code, ins->dreg, ins->dreg);
5220 break;
5221 case OP_ICONV_TO_R4_RAW:
5222 amd64_movd_xreg_reg_size (code, ins->dreg, ins->sreg1, 4);
5223 break;
5225 case OP_FCONV_TO_R8_X:
5226 s390x_movsd (code, ins->dreg, ins->sreg1);
5227 break;
5229 case OP_XCONV_R8_TO_I4:
5230 s390x_cvttsd2si_reg_xreg_size (code, ins->dreg, ins->sreg1, 4);
5231 switch (ins->backend.source_opcode) {
5232 case OP_FCONV_TO_I1:
5233 amd64_widen_reg (code, ins->dreg, ins->dreg, TRUE, FALSE);
5234 break;
5235 case OP_FCONV_TO_U1:
5236 amd64_widen_reg (code, ins->dreg, ins->dreg, FALSE, FALSE);
5237 break;
5238 case OP_FCONV_TO_I2:
5239 amd64_widen_reg (code, ins->dreg, ins->dreg, TRUE, TRUE);
5240 break;
5241 case OP_FCONV_TO_U2:
5242 amd64_widen_reg (code, ins->dreg, ins->dreg, FALSE, TRUE);
5243 break;
5245 break;
5247 case OP_EXPAND_I2:
5248 s390x_pinsrw_imm (code, ins->dreg, ins->sreg1, 0);
5249 s390x_pinsrw_imm (code, ins->dreg, ins->sreg1, 1);
5250 s390x_pshufd_imm (code, ins->dreg, ins->dreg, 0);
5251 break;
5252 case OP_EXPAND_I4:
5253 amd64_movd_xreg_reg_size (code, ins->dreg, ins->sreg1, 4);
5254 s390x_pshufd_imm (code, ins->dreg, ins->dreg, 0);
5255 break;
5256 case OP_EXPAND_I8:
5257 amd64_movd_xreg_reg_size (code, ins->dreg, ins->sreg1, 8);
5258 s390x_pshufd_imm (code, ins->dreg, ins->dreg, 0x44);
5259 break;
5260 case OP_EXPAND_R4:
5261 if (cfg->r4fp) {
5262 s390x_movsd (code, ins->dreg, ins->sreg1);
5263 } else {
5264 s390x_movsd (code, ins->dreg, ins->sreg1);
5265 s390x_cvtsd2ss (code, ins->dreg, ins->dreg);
5267 s390x_pshufd_imm (code, ins->dreg, ins->dreg, 0);
5268 break;
5269 case OP_EXPAND_R8:
5270 s390x_movsd (code, ins->dreg, ins->sreg1);
5271 s390x_pshufd_imm (code, ins->dreg, ins->dreg, 0x44);
5272 break;
5273 #endif
5274 default:
5275 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
5276 g_assert_not_reached ();
5279 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
5280 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
5281 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
5282 g_assert_not_reached ();
5286 set_code_cursor (cfg, code);
5289 /*========================= End of Function ========================*/
5291 /*------------------------------------------------------------------*/
5292 /* */
5293 /* Name - mono_arch_register_lowlevel_calls */
5294 /* */
5295 /* Function - Register routines to help with --trace operation. */
5296 /* */
5297 /*------------------------------------------------------------------*/
5299 void
5300 mono_arch_register_lowlevel_calls (void)
5304 /*========================= End of Function ========================*/
5306 /*------------------------------------------------------------------*/
5307 /* */
5308 /* Name - mono_arch_patch_code */
5309 /* */
5310 /* Function - Process the patch data created during the */
5311 /* instruction build process. This resolves jumps, */
5312 /* calls, variables etc. */
5313 /* */
5314 /*------------------------------------------------------------------*/
5316 void
5317 mono_arch_patch_code (MonoCompile *cfg, MonoMethod *method, MonoDomain *domain,
5318 guint8 *code, MonoJumpInfo *ji, gboolean run_cctors,
5319 MonoError *error)
5321 MonoJumpInfo *patch_info;
5323 error_init (error);
5325 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
5326 unsigned char *ip = patch_info->ip.i + code;
5327 gconstpointer target = NULL;
5329 target = mono_resolve_patch_target (method, domain, code,
5330 patch_info, run_cctors, error);
5331 return_if_nok (error);
5333 switch (patch_info->type) {
5334 case MONO_PATCH_INFO_IP:
5335 case MONO_PATCH_INFO_LDSTR:
5336 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
5337 case MONO_PATCH_INFO_LDTOKEN:
5338 case MONO_PATCH_INFO_EXC:
5339 s390_patch_addr (ip, (guint64) target);
5340 continue;
5341 case MONO_PATCH_INFO_JIT_ICALL: //temporary
5342 g_assert (!13);
5343 case MONO_PATCH_INFO_TRAMPOLINE_FUNC_ADDR:
5344 case MONO_PATCH_INFO_SPECIFIC_TRAMPOLINE_LAZY_FETCH_ADDR:
5345 case MONO_PATCH_INFO_METHOD:
5346 case MONO_PATCH_INFO_JIT_ICALL_ID:
5347 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
5348 case MONO_PATCH_INFO_RGCTX_FETCH:
5349 case MONO_PATCH_INFO_ABS: {
5350 S390_EMIT_CALL (ip, target);
5351 continue;
5353 case MONO_PATCH_INFO_SWITCH:
5354 /*----------------------------------*/
5355 /* ip points at the basr r13,0/j +4 */
5356 /* instruction the vtable value */
5357 /* follows this (i.e. ip+6) */
5358 /*----------------------------------*/
5359 S390_EMIT_LOAD (ip, target);
5360 continue;
5361 case MONO_PATCH_INFO_METHODCONST:
5362 case MONO_PATCH_INFO_CLASS:
5363 case MONO_PATCH_INFO_IMAGE:
5364 case MONO_PATCH_INFO_FIELD:
5365 case MONO_PATCH_INFO_IID:
5366 case MONO_PATCH_INFO_EXC_NAME:
5367 target = S390_RELATIVE(target, ip);
5368 s390_patch_rel (ip, (guint64) target);
5369 continue;
5370 case MONO_PATCH_INFO_R4:
5371 case MONO_PATCH_INFO_R8:
5372 case MONO_PATCH_INFO_METHOD_REL:
5373 g_assert_not_reached ();
5374 continue;
5375 default:
5376 target = S390_RELATIVE(target, ip);
5377 ip += 2;
5378 s390_patch_rel (ip, (guint64) target);
5383 /*========================= End of Function ========================*/
5385 /*------------------------------------------------------------------*/
5386 /* */
5387 /* Name - mono_arch_emit_prolog */
5388 /* */
5389 /* Function - Create the instruction sequence for a function */
5390 /* prolog. */
5391 /* */
5392 /*------------------------------------------------------------------*/
5394 guint8 *
5395 mono_arch_emit_prolog (MonoCompile *cfg)
5397 MonoMethod *method = cfg->method;
5398 MonoBasicBlock *bb;
5399 MonoMethodSignature *sig;
5400 MonoInst *inst;
5401 long alloc_size, pos, max_offset, i, cfa_offset = 0;
5402 guint8 *code;
5403 guint32 size;
5404 CallInfo *cinfo;
5405 int argsClobbered = 0,
5406 lmfOffset,
5407 fpOffset = 0;
5409 cfg->code_size = 512;
5411 if (method->save_lmf)
5412 cfg->code_size += 200;
5414 cfg->native_code = code = g_malloc (cfg->code_size);
5416 mono_emit_unwind_op_def_cfa (cfg, code, STK_BASE, 0);
5417 emit_unwind_regs(cfg, code, s390_r6, s390_r14, S390_REG_SAVE_OFFSET);
5418 s390_stmg (code, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
5419 mono_emit_unwind_op_offset (cfg, code, s390_r14, S390_RET_ADDR_OFFSET);
5420 mini_gc_set_slot_type_from_cfa (cfg, S390_RET_ADDR_OFFSET, SLOT_NOREF);
5421 if (cfg->arch.bkchain_reg != -1)
5422 s390_lgr (code, cfg->arch.bkchain_reg, STK_BASE);
5424 if (cfg->flags & MONO_CFG_HAS_ALLOCA) {
5425 cfg->used_int_regs |= 1 << s390_r11;
5428 if ((cfg->arch.used_fp_regs & S390_FP_SAVE_MASK) != 0) {
5429 for (int i=8; i<16; i++) {
5430 if (cfg->arch.used_fp_regs & (1 << i))
5431 fpOffset += sizeof(double);
5433 fpOffset = S390_ALIGN(fpOffset, 16);
5435 cfg->arch.fpSize = fpOffset;
5437 alloc_size = cfg->stack_offset + fpOffset;
5439 cfg->stack_usage = cfa_offset = alloc_size;
5440 s390_lgr (code, s390_r11, STK_BASE);
5441 if (s390_is_imm16 (alloc_size)) {
5442 s390_aghi (code, STK_BASE, -alloc_size);
5443 } else if (s390_is_imm32 (alloc_size)) {
5444 s390_agfi (code, STK_BASE, -alloc_size);
5445 } else {
5446 int stackSize = alloc_size;
5447 while (stackSize > INT_MAX) {
5448 s390_agfi (code, STK_BASE, -INT_MAX);
5449 stackSize -= INT_MAX;
5451 s390_agfi (code, STK_BASE, -stackSize);
5453 s390_stg (code, s390_r11, 0, STK_BASE, 0);
5455 if (fpOffset > 0) {
5456 int stkOffset = 0;
5458 s390_lgr (code, s390_r1, s390_r11);
5459 s390_aghi (code, s390_r1, -fpOffset);
5460 for (int i=8; i<16; i++) {
5461 if (cfg->arch.used_fp_regs & (1 << i)) {
5462 emit_unwind_regs(cfg, code, 16+i, 16+i, stkOffset+fpOffset);
5463 s390_std (code, i, 0, s390_r1, stkOffset);
5464 stkOffset += sizeof(double);
5469 mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
5471 if (cfg->frame_reg != STK_BASE)
5472 s390_lgr (code, s390_r11, STK_BASE);
5474 mono_emit_unwind_op_def_cfa_reg (cfg, code, cfg->frame_reg);
5476 /* store runtime generic context */
5477 if (cfg->rgctx_var) {
5478 g_assert (cfg->rgctx_var->opcode == OP_REGOFFSET);
5480 s390_stg (code, MONO_ARCH_RGCTX_REG, 0,
5481 cfg->rgctx_var->inst_basereg,
5482 cfg->rgctx_var->inst_offset);
5485 /* compute max_offset in order to use short forward jumps
5486 * we always do it on s390 because the immediate displacement
5487 * for jumps is too small
5489 max_offset = 0;
5490 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
5491 MonoInst *ins;
5492 bb->max_offset = max_offset;
5494 MONO_BB_FOR_EACH_INS (bb, ins)
5495 max_offset += ins_get_size (ins->opcode);
5498 /* load arguments allocated to register from the stack */
5499 sig = mono_method_signature_internal (method);
5500 pos = 0;
5502 cinfo = get_call_info (cfg->mempool, sig);
5504 if (cinfo->struct_ret) {
5505 ArgInfo *ainfo = &cinfo->ret;
5506 inst = cfg->vret_addr;
5507 inst->backend.size = ainfo->vtsize;
5508 s390_stg (code, ainfo->reg, 0, inst->inst_basereg, inst->inst_offset);
5511 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
5512 ArgInfo *ainfo = cinfo->args + i;
5513 inst = cfg->args [pos];
5515 if (inst->opcode == OP_VTARG_ADDR)
5516 inst = inst->inst_left;
5518 if (inst->opcode == OP_REGVAR) {
5519 if (ainfo->regtype == RegTypeGeneral)
5520 s390_lgr (code, inst->dreg, ainfo->reg);
5521 else if (ainfo->regtype == RegTypeFP) {
5522 if (inst->dreg != ainfo->reg) {
5523 s390_ldr (code, inst->dreg, ainfo->reg);
5525 } else if (ainfo->regtype == RegTypeFPR4) {
5526 if (!cfg->r4fp)
5527 s390_ledbr (code, inst->dreg, ainfo->reg);
5528 } else if (ainfo->regtype == RegTypeBase) {
5529 s390_lgr (code, s390_r13, STK_BASE);
5530 s390_aghi (code, s390_r13, alloc_size);
5531 s390_lg (code, inst->dreg, 0, s390_r13, ainfo->offset);
5532 } else
5533 g_assert_not_reached ();
5535 if (cfg->verbose_level > 2)
5536 g_print ("Argument %d assigned to register %s\n",
5537 pos, mono_arch_regname (inst->dreg));
5538 } else {
5539 if (ainfo->regtype == RegTypeGeneral) {
5540 if (!((ainfo->reg >= 2) && (ainfo->reg <= 6)))
5541 g_assert_not_reached();
5542 switch (ainfo->size) {
5543 case 1:
5544 s390_stc (code, ainfo->reg, 0, inst->inst_basereg, inst->inst_offset);
5545 break;
5546 case 2:
5547 s390_sth (code, ainfo->reg, 0, inst->inst_basereg, inst->inst_offset);
5548 break;
5549 case 4:
5550 s390_st (code, ainfo->reg, 0, inst->inst_basereg, inst->inst_offset);
5551 break;
5552 case 8:
5553 s390_stg (code, ainfo->reg, 0, inst->inst_basereg, inst->inst_offset);
5554 break;
5556 } else if (ainfo->regtype == RegTypeBase) {
5557 } else if (ainfo->regtype == RegTypeFP) {
5558 s390_std (code, ainfo->reg, 0, inst->inst_basereg, inst->inst_offset);
5559 } else if (ainfo->regtype == RegTypeFPR4) {
5560 s390_ste (code, ainfo->reg, 0, inst->inst_basereg, inst->inst_offset);
5561 } else if (ainfo->regtype == RegTypeStructByVal) {
5562 int doffset = inst->inst_offset;
5563 int reg;
5564 if (ainfo->reg != STK_BASE)
5565 reg = ainfo->reg;
5566 else {
5567 reg = s390_r0;
5568 s390_lgr (code, s390_r13, STK_BASE);
5569 s390_aghi (code, s390_r13, alloc_size);
5572 size = (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE
5573 ? mono_class_native_size(mono_class_from_mono_type_internal (inst->inst_vtype), NULL)
5574 : ainfo->size);
5576 switch (size) {
5577 case 1:
5578 if (ainfo->reg == STK_BASE)
5579 s390_ic (code, reg, 0, s390_r13, ainfo->offset+7);
5580 s390_stc (code, reg, 0, inst->inst_basereg, doffset);
5581 break;
5582 case 2:
5583 if (ainfo->reg == STK_BASE)
5584 s390_lh (code, reg, 0, s390_r13, ainfo->offset+6);
5585 s390_sth (code, reg, 0, inst->inst_basereg, doffset);
5586 break;
5587 case 4:
5588 if (ainfo->reg == STK_BASE)
5589 s390_l (code, reg, 0, s390_r13, ainfo->offset+4);
5590 s390_st (code, reg, 0, inst->inst_basereg, doffset);
5591 break;
5592 case 8:
5593 if (ainfo->reg == STK_BASE)
5594 s390_lg (code, reg, 0, s390_r13, ainfo->offset);
5595 s390_stg (code, reg, 0, inst->inst_basereg, doffset);
5596 break;
5598 } else if (ainfo->regtype == RegTypeStructByAddr) {
5599 s390_stg (code, ainfo->reg, 0, inst->inst_basereg, inst->inst_offset);
5600 } else if (ainfo->regtype == RegTypeStructByAddrOnStack) {
5601 } else
5602 g_assert_not_reached ();
5604 pos++;
5607 if (method->save_lmf) {
5608 /*---------------------------------------------------------------*/
5609 /* build the MonoLMF structure on the stack - see mini-s390x.h */
5610 /*---------------------------------------------------------------*/
5611 lmfOffset = alloc_size - sizeof(MonoLMF);
5613 s390_lgr (code, s390_r13, cfg->frame_reg);
5614 s390_aghi (code, s390_r13, lmfOffset);
5616 /*---------------------------------------------------------------*/
5617 /* Preserve the parameter registers while we fix up the lmf */
5618 /*---------------------------------------------------------------*/
5619 s390_stmg (code, s390_r2, s390_r6, s390_r13,
5620 G_STRUCT_OFFSET(MonoLMF, pregs[0]));
5622 mini_gc_set_slot_type_from_fp (cfg, lmfOffset + MONO_STRUCT_OFFSET (MonoLMF, pregs[0]), SLOT_NOREF);
5623 mini_gc_set_slot_type_from_fp (cfg, lmfOffset + MONO_STRUCT_OFFSET (MonoLMF, pregs[1]), SLOT_NOREF);
5624 mini_gc_set_slot_type_from_fp (cfg, lmfOffset + MONO_STRUCT_OFFSET (MonoLMF, pregs[2]), SLOT_NOREF);
5625 mini_gc_set_slot_type_from_fp (cfg, lmfOffset + MONO_STRUCT_OFFSET (MonoLMF, pregs[3]), SLOT_NOREF);
5626 mini_gc_set_slot_type_from_fp (cfg, lmfOffset + MONO_STRUCT_OFFSET (MonoLMF, pregs[4]), SLOT_NOREF);
5628 /*---------------------------------------------------------------*/
5629 /* On return from this call r2 have the address of the &lmf */
5630 /*---------------------------------------------------------------*/
5631 mono_add_patch_info (cfg, code - cfg->native_code,
5632 MONO_PATCH_INFO_JIT_ICALL_ID,
5633 GUINT_TO_POINTER (MONO_JIT_ICALL_mono_tls_get_lmf_addr));
5634 S390_CALL_TEMPLATE(code, s390_r1);
5636 /*---------------------------------------------------------------*/
5637 /* Set lmf.lmf_addr = jit_tls->lmf */
5638 /*---------------------------------------------------------------*/
5639 s390_stg (code, s390_r2, 0, s390_r13,
5640 G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5641 mini_gc_set_slot_type_from_fp (cfg, lmfOffset + MONO_STRUCT_OFFSET (MonoLMF, lmf_addr), SLOT_NOREF);
5643 /*---------------------------------------------------------------*/
5644 /* Get current lmf */
5645 /*---------------------------------------------------------------*/
5646 s390_lg (code, s390_r0, 0, s390_r2, 0);
5648 /*---------------------------------------------------------------*/
5649 /* Set our lmf as the current lmf */
5650 /*---------------------------------------------------------------*/
5651 s390_stg (code, s390_r13, 0, s390_r2, 0);
5653 /*---------------------------------------------------------------*/
5654 /* Have our lmf.previous_lmf point to the last lmf */
5655 /*---------------------------------------------------------------*/
5656 s390_stg (code, s390_r0, 0, s390_r13,
5657 G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5658 mini_gc_set_slot_type_from_fp (cfg, lmfOffset + MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), SLOT_NOREF);
5660 /*---------------------------------------------------------------*/
5661 /* save method info */
5662 /*---------------------------------------------------------------*/
5663 S390_SET (code, s390_r1, method);
5664 s390_stg (code, s390_r1, 0, s390_r13,
5665 G_STRUCT_OFFSET(MonoLMF, method));
5666 mini_gc_set_slot_type_from_fp (cfg, lmfOffset + MONO_STRUCT_OFFSET (MonoLMF, method), SLOT_NOREF);
5668 /*---------------------------------------------------------------*/
5669 /* save the current IP */
5670 /*---------------------------------------------------------------*/
5671 s390_stg (code, STK_BASE, 0, s390_r13, G_STRUCT_OFFSET(MonoLMF, ebp));
5672 s390_basr (code, s390_r1, 0);
5673 s390_stg (code, s390_r1, 0, s390_r13, G_STRUCT_OFFSET(MonoLMF, eip));
5674 mini_gc_set_slot_type_from_fp (cfg, lmfOffset + MONO_STRUCT_OFFSET (MonoLMF, ebp), SLOT_NOREF);
5675 mini_gc_set_slot_type_from_fp (cfg, lmfOffset + MONO_STRUCT_OFFSET (MonoLMF, eip), SLOT_NOREF);
5677 /*---------------------------------------------------------------*/
5678 /* Save general and floating point registers */
5679 /*---------------------------------------------------------------*/
5680 s390_stmg (code, s390_r2, s390_r12, s390_r13,
5681 G_STRUCT_OFFSET(MonoLMF, gregs[2]));
5682 mini_gc_set_slot_type_from_fp (cfg, lmfOffset + MONO_STRUCT_OFFSET (MonoLMF, gregs[0]), SLOT_NOREF);
5683 mini_gc_set_slot_type_from_fp (cfg, lmfOffset + MONO_STRUCT_OFFSET (MonoLMF, gregs[1]), SLOT_NOREF);
5684 mini_gc_set_slot_type_from_fp (cfg, lmfOffset + MONO_STRUCT_OFFSET (MonoLMF, gregs[2]), SLOT_NOREF);
5685 mini_gc_set_slot_type_from_fp (cfg, lmfOffset + MONO_STRUCT_OFFSET (MonoLMF, gregs[3]), SLOT_NOREF);
5686 mini_gc_set_slot_type_from_fp (cfg, lmfOffset + MONO_STRUCT_OFFSET (MonoLMF, gregs[4]), SLOT_NOREF);
5687 mini_gc_set_slot_type_from_fp (cfg, lmfOffset + MONO_STRUCT_OFFSET (MonoLMF, gregs[5]), SLOT_NOREF);
5688 mini_gc_set_slot_type_from_fp (cfg, lmfOffset + MONO_STRUCT_OFFSET (MonoLMF, gregs[6]), SLOT_NOREF);
5689 mini_gc_set_slot_type_from_fp (cfg, lmfOffset + MONO_STRUCT_OFFSET (MonoLMF, gregs[7]), SLOT_NOREF);
5690 mini_gc_set_slot_type_from_fp (cfg, lmfOffset + MONO_STRUCT_OFFSET (MonoLMF, gregs[8]), SLOT_NOREF);
5691 mini_gc_set_slot_type_from_fp (cfg, lmfOffset + MONO_STRUCT_OFFSET (MonoLMF, gregs[9]), SLOT_NOREF);
5692 mini_gc_set_slot_type_from_fp (cfg, lmfOffset + MONO_STRUCT_OFFSET (MonoLMF, gregs[10]), SLOT_NOREF);
5694 fpOffset = lmfOffset + MONO_STRUCT_OFFSET (MonoLMF, fregs[0]);
5695 for (i = 0; i < 16; i++) {
5696 s390_std (code, i, 0, s390_r13,
5697 G_STRUCT_OFFSET(MonoLMF, fregs[i]));
5698 mini_gc_set_slot_type_from_fp (cfg, fpOffset, SLOT_NOREF);
5699 fpOffset += sizeof(double);
5702 /*---------------------------------------------------------------*/
5703 /* Restore the parameter registers now that we've set up the lmf */
5704 /*---------------------------------------------------------------*/
5705 s390_lmg (code, s390_r2, s390_r6, s390_r13,
5706 G_STRUCT_OFFSET(MonoLMF, pregs[0]));
5709 if (cfg->method->save_lmf)
5710 argsClobbered = TRUE;
5713 * Optimize the common case of the first bblock making a call with the same
5714 * arguments as the method. This works because the arguments are still in their
5715 * original argument registers.
5717 if (!argsClobbered) {
5718 MonoBasicBlock *first_bb = cfg->bb_entry;
5719 MonoInst *next;
5720 int filter = FILTER_IL_SEQ_POINT;
5722 next = mono_bb_first_inst (first_bb, filter);
5723 if (!next && first_bb->next_bb) {
5724 first_bb = first_bb->next_bb;
5725 next = mono_bb_first_inst (first_bb, filter);
5728 if (first_bb->in_count > 1)
5729 next = NULL;
5731 for (i = 0; next && i < sig->param_count + sig->hasthis; ++i) {
5732 ArgInfo *ainfo = cinfo->args + i;
5733 gboolean match = FALSE;
5735 inst = cfg->args [i];
5736 if (inst->opcode != OP_REGVAR) {
5737 switch (ainfo->regtype) {
5738 case RegTypeGeneral: {
5739 if (((next->opcode == OP_LOAD_MEMBASE) ||
5740 (next->opcode == OP_LOADI4_MEMBASE)) &&
5741 next->inst_basereg == inst->inst_basereg &&
5742 next->inst_offset == inst->inst_offset) {
5743 if (next->dreg == ainfo->reg) {
5744 NULLIFY_INS (next);
5745 match = TRUE;
5746 } else {
5747 next->opcode = OP_MOVE;
5748 next->sreg1 = ainfo->reg;
5749 /* Only continue if the instruction doesn't change argument regs */
5750 if (next->dreg == ainfo->reg)
5751 match = TRUE;
5754 break;
5756 default:
5757 break;
5759 } else {
5760 /* Argument allocated to (non-volatile) register */
5761 switch (ainfo->regtype) {
5762 case RegTypeGeneral:
5763 if (next->opcode == OP_MOVE &&
5764 next->sreg1 == inst->dreg &&
5765 next->dreg == ainfo->reg) {
5766 NULLIFY_INS (next);
5767 match = TRUE;
5769 break;
5770 default:
5771 break;
5775 if (match) {
5776 next = mono_inst_next (next, filter);
5777 if (!next)
5778 break;
5783 set_code_cursor (cfg, code);
5785 return code;
5788 /*========================= End of Function ========================*/
5790 /*------------------------------------------------------------------*/
5791 /* */
5792 /* Name - mono_arch_emit_epilog */
5793 /* */
5794 /* Function - Emit the instructions for a function epilog. */
5795 /* */
5796 /*------------------------------------------------------------------*/
5798 void
5799 mono_arch_emit_epilog (MonoCompile *cfg)
5801 MonoMethod *method = cfg->method;
5802 guint8 *code;
5803 int max_epilog_size = 96;
5804 int fpOffset = 0;
5806 if (cfg->method->save_lmf)
5807 max_epilog_size += 128;
5809 code = realloc_code (cfg, max_epilog_size);
5811 if (method->save_lmf)
5812 restoreLMF(code, cfg->frame_reg, cfg->stack_usage);
5814 code = backUpStackPtr(cfg, code);
5816 if (cfg->arch.fpSize != 0) {
5817 fpOffset = -cfg->arch.fpSize;
5818 for (int i=8; i<16; i++) {
5819 if (cfg->arch.used_fp_regs & (1 << i)) {
5820 s390_ldy (code, i, 0, STK_BASE, fpOffset);
5821 fpOffset += sizeof(double);
5826 s390_lmg (code, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
5827 s390_br (code, s390_r14);
5829 set_code_cursor (cfg, code);
5833 /*========================= End of Function ========================*/
5835 /*------------------------------------------------------------------*/
5836 /* */
5837 /* Name - mono_arch_emit_exceptions */
5838 /* */
5839 /* Function - Emit the blocks to handle exception conditions. */
5840 /* */
5841 /*------------------------------------------------------------------*/
5843 void
5844 mono_arch_emit_exceptions (MonoCompile *cfg)
5846 MonoJumpInfo *patch_info;
5847 guint8 *code;
5848 int nThrows = 0,
5849 exc_count = 0,
5850 iExc;
5851 guint32 code_size;
5852 MonoClass *exc_classes [MAX_EXC];
5853 guint8 *exc_throw_start [MAX_EXC];
5855 for (patch_info = cfg->patch_info;
5856 patch_info;
5857 patch_info = patch_info->next) {
5858 if (patch_info->type == MONO_PATCH_INFO_EXC)
5859 exc_count++;
5862 code_size = exc_count * 48;
5864 code = realloc_code (cfg, code_size);
5866 /*---------------------------------------------------------------------*/
5867 /* Add code to raise exceptions */
5868 /*---------------------------------------------------------------------*/
5869 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5870 switch (patch_info->type) {
5871 case MONO_PATCH_INFO_EXC: {
5872 guint8 *ip = patch_info->ip.i + cfg->native_code;
5873 MonoClass *exc_class;
5874 guint64 throw_ip;
5876 /*-----------------------------------------------------*/
5877 /* Patch the branch in epilog to come here */
5878 /*-----------------------------------------------------*/
5879 s390_patch_rel (ip + 2, (guint64) S390_RELATIVE(code,ip));
5881 exc_class = mono_class_load_from_name (mono_defaults.corlib,
5882 "System",
5883 patch_info->data.name);
5884 throw_ip = patch_info->ip.i;
5886 for (iExc = 0; iExc < nThrows; ++iExc)
5887 if (exc_classes [iExc] == exc_class)
5888 break;
5890 if (iExc < nThrows) {
5891 s390_jcl (code, S390_CC_UN,
5892 (guint64) exc_throw_start [iExc]);
5893 patch_info->type = MONO_PATCH_INFO_NONE;
5894 } else {
5896 if (nThrows < MAX_EXC) {
5897 exc_classes [nThrows] = exc_class;
5898 exc_throw_start [nThrows] = code;
5901 /*---------------------------------------------*/
5902 /* Patch the parameter passed to the handler */
5903 /*---------------------------------------------*/
5904 S390_SET (code, s390_r2, m_class_get_type_token (exc_class));
5905 /*---------------------------------------------*/
5906 /* Load return address & parameter register */
5907 /*---------------------------------------------*/
5908 s390_larl (code, s390_r14, (guint64)S390_RELATIVE((patch_info->ip.i +
5909 cfg->native_code + 8), code));
5910 /*---------------------------------------------*/
5911 /* Reuse the current patch to set the jump */
5912 /*---------------------------------------------*/
5913 patch_info->type = MONO_PATCH_INFO_JIT_ICALL_ID;
5914 patch_info->data.jit_icall_id = MONO_JIT_ICALL_mono_arch_throw_corlib_exception;
5915 patch_info->ip.i = code - cfg->native_code;
5916 S390_BR_TEMPLATE (code, s390_r1);
5918 break;
5920 default:
5921 /* do nothing */
5922 break;
5925 set_code_cursor (cfg, code);
5928 /*========================= End of Function ========================*/
5930 /*------------------------------------------------------------------*/
5931 /* */
5932 /* Name - mono_arch_finish_init */
5933 /* */
5934 /* Function - Setup the JIT's Thread Level Specific Data. */
5935 /* */
5936 /*------------------------------------------------------------------*/
5938 void
5939 mono_arch_finish_init (void)
5943 /*========================= End of Function ========================*/
5945 /*------------------------------------------------------------------*/
5946 /* */
5947 /* Name - mono_arch_free_jit_tls_data */
5948 /* */
5949 /* Function - Free tls data. */
5950 /* */
5951 /*------------------------------------------------------------------*/
5953 void
5954 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5958 /*========================= End of Function ========================*/
5960 /*------------------------------------------------------------------*/
5961 /* */
5962 /* Name - mono_arch_emit_inst_for_method */
5963 /* */
5964 /*------------------------------------------------------------------*/
5966 MonoInst*
5967 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5969 return NULL;
5972 /*========================= End of Function ========================*/
5974 /*------------------------------------------------------------------*/
5975 /* */
5976 /* Name - mono_arch_decompose_opts */
5977 /* */
5978 /* Function - Decompose opcode into a System z opcode. */
5979 /* */
5980 /*------------------------------------------------------------------*/
5982 void
5983 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
5986 * Have to rename these to avoid being decomposed normally, since the normal
5987 * decomposition does not work on S390.
5989 switch (ins->opcode) {
5990 case OP_ISUB_OVF:
5991 ins->opcode = OP_S390_ISUB_OVF;
5992 break;
5993 case OP_ISUB_OVF_UN:
5994 ins->opcode = OP_S390_ISUB_OVF_UN;
5995 break;
5996 case OP_IADD_OVF:
5997 ins->opcode = OP_S390_IADD_OVF;
5998 break;
5999 case OP_IADD_OVF_UN:
6000 ins->opcode = OP_S390_IADD_OVF_UN;
6001 break;
6002 case OP_LADD_OVF:
6003 ins->opcode = OP_S390_LADD_OVF;
6004 break;
6005 case OP_LADD_OVF_UN:
6006 ins->opcode = OP_S390_LADD_OVF_UN;
6007 break;
6008 case OP_LSUB_OVF:
6009 ins->opcode = OP_S390_LSUB_OVF;
6010 break;
6011 case OP_LSUB_OVF_UN:
6012 ins->opcode = OP_S390_LSUB_OVF_UN;
6013 break;
6014 default:
6015 break;
6019 /*========================= End of Function ========================*/
6021 /*------------------------------------------------------------------*/
6022 /* */
6023 /* Name - mono_arch_regalloc_cost */
6024 /* */
6025 /* Function - Determine the cost, in the number of memory */
6026 /* references, of the action of allocating the var- */
6027 /* iable VMV into a register during global register */
6028 /* allocation. */
6029 /* */
6030 /* Returns - Cost */
6031 /* */
6032 /*------------------------------------------------------------------*/
6034 guint32
6035 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
6037 /* FIXME: */
6038 return 2;
6041 /*========================= End of Function ========================*/
6043 /*------------------------------------------------------------------*/
6044 /* */
6045 /* Name - mono_arch_flush_register_windows */
6046 /* */
6047 /* Function - */
6048 /* */
6049 /* Returns - */
6050 /* */
6051 /*------------------------------------------------------------------*/
6053 void
6054 mono_arch_flush_register_windows (void)
6058 /*========================= End of Function ========================*/
6060 /*------------------------------------------------------------------*/
6061 /* */
6062 /* Name - mono_arch_is_inst_imm */
6063 /* */
6064 /* Function - Determine if operand qualifies as an immediate */
6065 /* value. For s390 this is a value -32768-32768 */
6066 /* */
6067 /* Returns - True|False - is [not] immediate value. */
6068 /* */
6069 /*------------------------------------------------------------------*/
6071 gboolean
6072 mono_arch_is_inst_imm (int opcode, int imm_opcode, gint64 imm)
6074 return s390_is_imm32 (imm);
6077 /*========================= End of Function ========================*/
6079 /*------------------------------------------------------------------*/
6080 /* */
6081 /* Name - mono_arch_get_patch_offset */
6082 /* */
6083 /* Function - Dummy entry point until s390x supports aot. */
6084 /* */
6085 /* Returns - Offset for patch. */
6086 /* */
6087 /*------------------------------------------------------------------*/
6089 guint32
6090 mono_arch_get_patch_offset (guint8 *code)
6092 return 0;
6095 /*========================= End of Function ========================*/
6097 /*------------------------------------------------------------------*/
6098 /* */
6099 /* Name - mono_arch_context_get_int_reg. */
6100 /* */
6101 /* Function - */
6102 /* */
6103 /* Returns - Return a register from the context. */
6104 /* */
6105 /*------------------------------------------------------------------*/
6107 host_mgreg_t
6108 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
6110 return ctx->uc_mcontext.gregs[reg];
6113 /*========================= End of Function ========================*/
6115 /*------------------------------------------------------------------*/
6116 /* */
6117 /* Name - mono_arch_context_set_int_reg. */
6118 /* */
6119 /* Function - Set a value in a specified register. */
6120 /* */
6121 /*------------------------------------------------------------------*/
6123 void
6124 mono_arch_context_set_int_reg (MonoContext *ctx, int reg, host_mgreg_t val)
6126 ctx->uc_mcontext.gregs[reg] = val;
6129 /*========================= End of Function ========================*/
6131 /*------------------------------------------------------------------*/
6132 /* */
6133 /* Name - mono_arch_get_this_arg_from_call. */
6134 /* */
6135 /* Function - */
6136 /* */
6137 /*------------------------------------------------------------------*/
6139 gpointer
6140 mono_arch_get_this_arg_from_call (host_mgreg_t *regs, guint8 *code)
6142 return (gpointer) regs [s390_r2];
6145 /*========================= End of Function ========================*/
6147 /*------------------------------------------------------------------*/
6148 /* */
6149 /* Name - get_delegate_invoke_impl. */
6150 /* */
6151 /* Function - */
6152 /* */
6153 /*------------------------------------------------------------------*/
6155 static guint8*
6156 get_delegate_invoke_impl (MonoTrampInfo **info, gboolean has_target, guint32 param_count, gboolean aot)
6158 guint8 *code, *start;
6160 if (has_target) {
6161 int size = 32;
6163 start = code = mono_global_codeman_reserve (size);
6165 /* Replace the this argument with the target */
6166 s390_lg (code, s390_r1, 0, s390_r2, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
6167 s390_lg (code, s390_r2, 0, s390_r2, MONO_STRUCT_OFFSET (MonoDelegate, target));
6168 s390_br (code, s390_r1);
6169 g_assert ((code - start) <= size);
6171 mono_arch_flush_icache (start, size);
6172 MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_DELEGATE_INVOKE, NULL));
6173 } else {
6174 int size, i;
6176 size = 32 + param_count * 8;
6177 start = code = mono_global_codeman_reserve (size);
6179 s390_lg (code, s390_r1, 0, s390_r2, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
6180 /* slide down the arguments */
6181 for (i = 0; i < param_count; ++i) {
6182 s390_lgr (code, (s390_r2 + i), (s390_r2 + i + 1));
6184 s390_br (code, s390_r1);
6186 g_assert ((code - start) <= size);
6188 mono_arch_flush_icache (start, size);
6189 MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_DELEGATE_INVOKE, NULL));
6192 if (has_target) {
6193 *info = mono_tramp_info_create ("delegate_invoke_impl_has_target", start, code - start, NULL, NULL);
6194 } else {
6195 char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", param_count);
6196 *info = mono_tramp_info_create (name, start, code - start, NULL, NULL);
6197 g_free (name);
6200 return start;
6203 /*========================= End of Function ========================*/
6205 /*------------------------------------------------------------------*/
6206 /* */
6207 /* Name - mono_arch_get_delegate_invoke_impls. */
6208 /* */
6209 /* Function - */
6210 /* */
6211 /*------------------------------------------------------------------*/
6213 GSList*
6214 mono_arch_get_delegate_invoke_impls (void)
6216 GSList *res = NULL;
6217 MonoTrampInfo *info;
6218 int i;
6220 get_delegate_invoke_impl (&info, TRUE, 0, TRUE);
6221 res = g_slist_prepend (res, info);
6223 for (i = 0; i <= MAX_ARCH_DELEGATE_PARAMS; ++i) {
6224 get_delegate_invoke_impl (&info, FALSE, i, TRUE);
6225 res = g_slist_prepend (res, info);
6228 return res;
6231 /*========================= End of Function ========================*/
6233 /*------------------------------------------------------------------*/
6234 /* */
6235 /* Name - mono_arch_get_delegate_invoke_impl. */
6236 /* */
6237 /* Function - */
6238 /* */
6239 /*------------------------------------------------------------------*/
6241 gpointer
6242 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
6244 guint8 *code, *start;
6246 /* FIXME: Support more cases */
6247 if (MONO_TYPE_ISSTRUCT (sig->ret))
6248 return NULL;
6250 if (has_target) {
6251 static guint8* cached = NULL;
6253 if (cached)
6254 return cached;
6256 if (mono_ee_features.use_aot_trampolines) {
6257 start = mono_aot_get_trampoline ("delegate_invoke_impl_has_target");
6258 } else {
6259 MonoTrampInfo *info;
6260 start = get_delegate_invoke_impl (&info, TRUE, 0, FALSE);
6261 mono_tramp_info_register (info, NULL);
6264 mono_memory_barrier ();
6266 cached = start;
6267 } else {
6268 static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
6269 int i;
6271 if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
6272 return NULL;
6273 for (i = 0; i < sig->param_count; ++i)
6274 if (!mono_is_regsize_var (sig->params [i]))
6275 return NULL;
6278 code = cache [sig->param_count];
6279 if (code)
6280 return code;
6282 if (mono_ee_features.use_aot_trampolines) {
6283 char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", sig->param_count);
6284 start = mono_aot_get_trampoline (name);
6285 g_free (name);
6286 } else {
6287 MonoTrampInfo *info;
6288 start = get_delegate_invoke_impl (&info, FALSE, sig->param_count, FALSE);
6289 mono_tramp_info_register (info, NULL);
6292 mono_memory_barrier ();
6294 cache [sig->param_count] = start;
6296 return start;
6299 /*========================= End of Function ========================*/
6301 /*------------------------------------------------------------------*/
6302 /* */
6303 /* Name - mono_arch_get_delegate_virtual_invoke_impl. */
6304 /* */
6305 /* Function - */
6306 /* */
6307 /*------------------------------------------------------------------*/
6309 gpointer
6310 mono_arch_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method,
6311 int offset, gboolean load_imt_reg)
6313 guint8 *code, *start;
6314 int size = 40;
6316 start = code = mono_global_codeman_reserve (size);
6319 * Replace the "this" argument with the target
6321 s390_lgr (code, s390_r1, s390_r2);
6322 s390_lg (code, s390_r2, 0, s390_r1, MONO_STRUCT_OFFSET(MonoDelegate, target));
6325 * Load the IMT register, if needed
6327 if (load_imt_reg) {
6328 s390_lg (code, MONO_ARCH_IMT_REG, 0, s390_r1, MONO_STRUCT_OFFSET(MonoDelegate, method));
6332 * Load the vTable
6334 s390_lg (code, s390_r1, 0, s390_r2, MONO_STRUCT_OFFSET(MonoObject, vtable));
6335 if (offset != 0) {
6336 s390_agfi(code, s390_r1, offset);
6338 s390_lg (code, s390_r1, 0, s390_r1, 0);
6339 s390_br (code, s390_r1);
6341 mono_arch_flush_icache (start, code - start);
6342 MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_DELEGATE_INVOKE, NULL));
6344 return(start);
6347 /*========================= End of Function ========================*/
6349 /*------------------------------------------------------------------*/
6350 /* */
6351 /* Name - mono_arch_build_imt_trampoline. */
6352 /* */
6353 /* Function - */
6354 /* */
6355 /*------------------------------------------------------------------*/
6357 gpointer
6358 mono_arch_build_imt_trampoline (MonoVTable *vtable, MonoDomain *domain,
6359 MonoIMTCheckItem **imt_entries, int count,
6360 gpointer fail_tramp)
6362 int i;
6363 int size = 0;
6364 guchar *code, *start;
6365 char trampName[64];
6367 for (i = 0; i < count; ++i) {
6368 MonoIMTCheckItem *item = imt_entries [i];
6369 if (item->is_equals) {
6370 if (item->check_target_idx) {
6371 if (!item->compare_done)
6372 item->chunk_size += CMP_SIZE + JUMP_SIZE;
6373 if (item->has_target_code)
6374 item->chunk_size += BR_SIZE + JUMP_SIZE + LOADCON_SIZE;
6375 else
6376 item->chunk_size += BR_SIZE + JUMP_SIZE + LOADCON_SIZE +
6377 LOAD_SIZE;
6378 } else {
6379 if (fail_tramp) {
6380 item->chunk_size += CMP_SIZE + 2 * BR_SIZE + JUMP_SIZE +
6381 2 * LOADCON_SIZE;
6382 if (!item->has_target_code)
6383 item->chunk_size += LOAD_SIZE;
6384 } else {
6385 item->chunk_size += LOADCON_SIZE + LOAD_SIZE + BR_SIZE;
6386 #if ENABLE_WRONG_METHOD_CHECK
6387 item->chunk_size += CMP_SIZE + JUMP_SIZE;
6388 #endif
6391 } else {
6392 item->chunk_size += CMP_SIZE + JUMP_SIZE;
6393 imt_entries [item->check_target_idx]->compare_done = TRUE;
6395 size += item->chunk_size;
6398 if (fail_tramp)
6399 code = mono_method_alloc_generic_virtual_trampoline (domain, size);
6400 else
6401 code = mono_domain_code_reserve (domain, size);
6403 start = code;
6405 for (i = 0; i < count; ++i) {
6406 MonoIMTCheckItem *item = imt_entries [i];
6407 item->code_target = (guint8 *) code;
6408 if (item->is_equals) {
6409 if (item->check_target_idx) {
6410 if (!item->compare_done) {
6411 S390_SET (code, s390_r0, item->key);
6412 s390_cgr (code, s390_r0, MONO_ARCH_IMT_REG);
6414 item->jmp_code = (guint8*) code;
6415 s390_jcl (code, S390_CC_NE, 0);
6417 if (item->has_target_code) {
6418 S390_SET (code, s390_r1, item->value.target_code);
6419 } else {
6420 S390_SET (code, s390_r1, (&(vtable->vtable [item->value.vtable_slot])));
6421 s390_lg (code, s390_r1, 0, s390_r1, 0);
6423 s390_br (code, s390_r1);
6424 } else {
6425 if (fail_tramp) {
6426 gint64 target;
6428 S390_SET (code, s390_r0, item->key);
6429 s390_cgr (code, s390_r0, MONO_ARCH_IMT_REG);
6430 item->jmp_code = (guint8*) code;
6431 s390_jcl (code, S390_CC_NE, 0);
6432 if (item->has_target_code) {
6433 S390_SET (code, s390_r1, item->value.target_code);
6434 } else {
6435 g_assert (vtable);
6436 S390_SET (code, s390_r1,
6437 (&(vtable->vtable [item->value.vtable_slot])));
6438 s390_lg (code, s390_r1, 0, s390_r1, 0);
6440 s390_br (code, s390_r1);
6441 target = (gint64) S390_RELATIVE(code, item->jmp_code);
6442 s390_patch_rel(item->jmp_code+2, target);
6443 S390_SET (code, s390_r1, fail_tramp);
6444 s390_br (code, s390_r1);
6445 item->jmp_code = NULL;
6446 } else {
6447 /* enable the commented code to assert on wrong method */
6448 #if ENABLE_WRONG_METHOD_CHECK
6449 g_assert_not_reached ();
6450 #endif
6451 S390_SET (code, s390_r1, (&(vtable->vtable [item->value.vtable_slot])));
6452 s390_lg (code, s390_r1, 0, s390_r1, 0);
6453 s390_br (code, s390_r1);
6456 } else {
6457 S390_SET (code, s390_r0, item->key);
6458 s390_cgr (code, MONO_ARCH_IMT_REG, s390_r0);
6459 item->jmp_code = (guint8 *) code;
6460 s390_jcl (code, S390_CC_GE, 0);
6464 * patch the branches to get to the target items
6466 for (i = 0; i < count; ++i) {
6467 MonoIMTCheckItem *item = imt_entries [i];
6468 if (item->jmp_code) {
6469 if (item->check_target_idx) {
6470 gint64 offset;
6471 offset = (gint64) S390_RELATIVE(imt_entries [item->check_target_idx]->code_target,
6472 item->jmp_code);
6473 s390_patch_rel ((guchar *) item->jmp_code + 2, (guint64) offset);
6478 mono_arch_flush_icache ((guint8*)start, (code - start));
6479 MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_IMT_TRAMPOLINE, NULL));
6481 if (!fail_tramp)
6482 UnlockedAdd (&mono_stats.imt_trampolines_size, code - start);
6484 g_assert (code - start <= size);
6486 snprintf(trampName, sizeof(trampName), "%d_imt_trampoline", domain->domain_id);
6487 mono_tramp_info_register (mono_tramp_info_create (trampName, start, code - start, NULL, NULL), domain);
6489 return (start);
6492 /*========================= End of Function ========================*/
6494 /*------------------------------------------------------------------*/
6495 /* */
6496 /* Name - mono_arch_find_imt_method. */
6497 /* */
6498 /* Function - Get the method address from MONO_ARCH_IMT_REG */
6499 /* found in the save area. */
6500 /* */
6501 /*------------------------------------------------------------------*/
6503 MonoMethod*
6504 mono_arch_find_imt_method (host_mgreg_t *regs, guint8 *code)
6506 return ((MonoMethod *) regs [MONO_ARCH_IMT_REG]);
6509 /*========================= End of Function ========================*/
6511 /*------------------------------------------------------------------*/
6512 /* */
6513 /* Name - mono_arch_find_static_call_vtable */
6514 /* */
6515 /* Function - Find the static call vtable. */
6516 /* */
6517 /*------------------------------------------------------------------*/
6519 MonoVTable*
6520 mono_arch_find_static_call_vtable (host_mgreg_t *regs, guint8 *code)
6522 return (MonoVTable*)(gsize) regs [MONO_ARCH_RGCTX_REG];
6525 /*========================= End of Function ========================*/
6527 /*------------------------------------------------------------------*/
6528 /* */
6529 /* Name - mono_arch_get_cie_program */
6530 /* */
6531 /* Function - Find the static call vtable. */
6532 /* */
6533 /*------------------------------------------------------------------*/
6535 GSList*
6536 mono_arch_get_cie_program (void)
6538 GSList *l = NULL;
6540 mono_add_unwind_op_def_cfa (l, 0, 0, STK_BASE, 0);
6542 return(l);
6545 /*========================= End of Function ========================*/
6547 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
6549 /*------------------------------------------------------------------*/
6550 /* */
6551 /* Name - mono_arch_set_breakpoint. */
6552 /* */
6553 /* Function - Set a breakpoint at the native code corresponding */
6554 /* to JI at NATIVE_OFFSET. The location should */
6555 /* contain code emitted by OP_SEQ_POINT. */
6556 /* */
6557 /*------------------------------------------------------------------*/
6559 void
6560 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
6562 guint8 *code = ip;
6564 breakpointCode.pTrigger = bp_trigger_page;
6565 memcpy(code, (void *) &breakpointCode, BREAKPOINT_SIZE);
6566 code += BREAKPOINT_SIZE;
6569 /*========================= End of Function ========================*/
6571 /*------------------------------------------------------------------*/
6572 /* */
6573 /* Name - mono_arch_clear_breakpoint. */
6574 /* */
6575 /* Function - Clear the breakpoint at IP. */
6576 /* */
6577 /*------------------------------------------------------------------*/
6579 void
6580 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
6582 guint8 *code = ip;
6583 int i;
6585 for (i = 0; i < (BREAKPOINT_SIZE / S390X_NOP_SIZE); i++)
6586 s390_nop(code);
6589 /*========================= End of Function ========================*/
6591 /*------------------------------------------------------------------*/
6592 /* */
6593 /* Name - mono_arch_is_breakpoint_event. */
6594 /* */
6595 /* Function - */
6596 /* */
6597 /*------------------------------------------------------------------*/
6599 gboolean
6600 mono_arch_is_breakpoint_event (void *info, void *sigctx)
6602 siginfo_t* sinfo = (siginfo_t*) info;
6605 * Sometimes the address is off by 4
6607 if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
6608 return TRUE;
6609 else
6610 return FALSE;
6613 /*========================= End of Function ========================*/
6615 /*------------------------------------------------------------------*/
6616 /* */
6617 /* Name - mono_arch_skip_breakpoint. */
6618 /* */
6619 /* Function - Modify the CTX so the IP is placed after the */
6620 /* breakpoint instruction, so when we resume, the */
6621 /* instruction is not executed again. */
6622 /* */
6623 /*------------------------------------------------------------------*/
6625 void
6626 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
6628 MONO_CONTEXT_SET_IP (ctx, ((guint8*)MONO_CONTEXT_GET_IP (ctx) + sizeof(RXY_Format)));
6631 /*========================= End of Function ========================*/
6633 /*------------------------------------------------------------------*/
6634 /* */
6635 /* Name - mono_arch_start_single_stepping. */
6636 /* */
6637 /* Function - Start single stepping. */
6638 /* */
6639 /*------------------------------------------------------------------*/
6641 void
6642 mono_arch_start_single_stepping (void)
6644 mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
6647 /*========================= End of Function ========================*/
6649 /*------------------------------------------------------------------*/
6650 /* */
6651 /* Name - mono_arch_stop_single_stepping. */
6652 /* */
6653 /* Function - Stop single stepping. */
6654 /* */
6655 /*------------------------------------------------------------------*/
6657 void
6658 mono_arch_stop_single_stepping (void)
6660 mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
6663 /*========================= End of Function ========================*/
6665 /*------------------------------------------------------------------*/
6666 /* */
6667 /* Name - mono_arch_is_single_step_event. */
6668 /* */
6669 /* Function - Return whether the machine state in sigctx cor- */
6670 /* responds to a single step event. */
6671 /* */
6672 /*------------------------------------------------------------------*/
6674 gboolean
6675 mono_arch_is_single_step_event (void *info, void *sigctx)
6677 siginfo_t* sinfo = (siginfo_t*) info;
6680 * Sometimes the address is off by 4
6682 if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
6683 return TRUE;
6684 else
6685 return FALSE;
6688 /*========================= End of Function ========================*/
6690 /*------------------------------------------------------------------*/
6691 /* */
6692 /* Name - mono_arch_skip_single_step. */
6693 /* */
6694 /* Function - Modify the ctx so the IP is placed after the */
6695 /* single step trigger instruction, so that the */
6696 /* instruction is not executed again. */
6697 /* */
6698 /*------------------------------------------------------------------*/
6700 void
6701 mono_arch_skip_single_step (MonoContext *ctx)
6703 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + BREAKPOINT_SIZE);
6706 /*========================= End of Function ========================*/
6708 /*------------------------------------------------------------------*/
6709 /* */
6710 /* Name - mono_arch_create_seq_point_info. */
6711 /* */
6712 /* Function - Return a pointer to a data struction which is */
6713 /* used by the sequence point implementation in */
6714 /* AOTed code. */
6715 /* */
6716 /*------------------------------------------------------------------*/
6718 SeqPointInfo*
6719 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
6721 NOT_IMPLEMENTED;
6722 return NULL;
6725 /*========================= End of Function ========================*/
6727 #endif
6729 /*------------------------------------------------------------------*/
6730 /* */
6731 /* Name - mono_arch_cpu_enumerate_simd_versions. */
6732 /* */
6733 /* Function - If this CPU supports vector operations then it */
6734 /* supports the equivalent of SSE1-4. */
6735 /* */
6736 /*------------------------------------------------------------------*/
6738 guint32
6739 mono_arch_cpu_enumerate_simd_versions (void)
6741 guint32 sseOpts = 0;
6743 if (mono_hwcap_s390x_has_vec)
6744 sseOpts = (SIMD_VERSION_SSE1 | SIMD_VERSION_SSE2 |
6745 SIMD_VERSION_SSE3 | SIMD_VERSION_SSSE3 |
6746 SIMD_VERSION_SSE41 | SIMD_VERSION_SSE42 |
6747 SIMD_VERSION_SSE4a);
6749 return (sseOpts);
6752 /*========================= End of Function ========================*/
6754 /*------------------------------------------------------------------*/
6755 /* */
6756 /* Name - mono_arch_opcode_supported. */
6757 /* */
6758 /* Function - Check if a given op code is supported. */
6759 /* */
6760 /*------------------------------------------------------------------*/
6762 gboolean
6763 mono_arch_opcode_supported (int opcode)
6765 switch (opcode) {
6766 case OP_ATOMIC_ADD_I4:
6767 case OP_ATOMIC_ADD_I8:
6768 case OP_ATOMIC_EXCHANGE_I4:
6769 case OP_ATOMIC_EXCHANGE_I8:
6770 return TRUE;
6771 default:
6772 return FALSE;
6776 /*========================= End of Function ========================*/
6778 /*------------------------------------------------------------------*/
6779 /* */
6780 /* Name - mono_arch_tailcall_supported. */
6781 /* */
6782 /* Function - Check if a tailcall is supported. */
6783 /* */
6784 /*------------------------------------------------------------------*/
6786 #ifndef DISABLE_JIT
6788 gboolean
6789 mono_arch_tailcall_supported (MonoCompile *cfg, MonoMethodSignature *caller_sig, MonoMethodSignature *callee_sig, gboolean virtual_)
6791 g_assert (caller_sig);
6792 g_assert (callee_sig);
6794 CallInfo *caller_info = get_call_info (NULL, caller_sig);
6795 CallInfo *callee_info = get_call_info (NULL, callee_sig);
6797 gboolean res = IS_SUPPORTED_TAILCALL (callee_info->stack_usage <= caller_info->stack_usage)
6798 && IS_SUPPORTED_TAILCALL (callee_info->struct_ret == caller_info->struct_ret)
6799 && IS_SUPPORTED_TAILCALL (memcmp (&callee_info->ret, &caller_info->ret, sizeof (caller_info->ret)) == 0);
6801 // valuetypes passed semantic-byvalue ABI-byref are often to a local.
6802 // FIXME ABIs vary as to if this local is in the parameter area or not,
6803 // so this check might not be needed.
6804 ArgInfo const * const ainfo = callee_info->args + callee_sig->hasthis;
6805 for (int i = 0; res && i < callee_sig->param_count; ++i) {
6806 res = IS_SUPPORTED_TAILCALL (ainfo [i].regtype != RegTypeStructByAddr)
6807 && IS_SUPPORTED_TAILCALL (ainfo [i].regtype != RegTypeStructByAddrOnStack);
6810 g_free (caller_info);
6811 g_free (callee_info);
6813 return res;
6816 #endif
6818 /*========================= End of Function ========================*/