[llvm] Mark Vector128/Vector256 types as SIMD.
[mono-project.git] / mono / mini / mini-s390x.c
blob220af9303b790cd6e9ba0e257d703d4adad98b57
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 /*========================= End of Defines =========================*/
312 /*------------------------------------------------------------------*/
313 /* I n c l u d e s */
314 /*------------------------------------------------------------------*/
316 #include "mini.h"
317 #include <string.h>
318 #include <sys/types.h>
319 #include <unistd.h>
321 #include <mono/metadata/abi-details.h>
322 #include <mono/metadata/appdomain.h>
323 #include <mono/metadata/debug-helpers.h>
324 #include <mono/metadata/profiler-private.h>
325 #include <mono/utils/mono-error.h>
326 #include <mono/utils/mono-error-internals.h>
327 #include <mono/utils/mono-math.h>
328 #include <mono/utils/mono-mmap.h>
329 #include <mono/utils/mono-hwcap.h>
330 #include <mono/utils/mono-threads.h>
331 #include <mono/utils/unlocked.h>
333 #include "mini-s390x.h"
334 #include "cpu-s390x.h"
335 #include "support-s390x.h"
336 #include "jit-icalls.h"
337 #include "ir-emit.h"
338 #include "mini-gc.h"
339 #include "aot-runtime.h"
340 #include "mini-runtime.h"
342 /*========================= End of Includes ========================*/
344 /*------------------------------------------------------------------*/
345 /* T y p e d e f s */
346 /*------------------------------------------------------------------*/
348 typedef struct {
349 guint stack_size,
350 local_size,
351 code_size,
352 parm_size,
353 offset,
354 offStruct,
355 retStruct;
356 } size_data;
358 typedef struct InstList InstList;
360 struct InstList {
361 InstList *prev;
362 InstList *next;
363 MonoInst *data;
366 typedef enum {
367 RegTypeGeneral,
368 RegTypeBase,
369 RegTypeFP,
370 RegTypeFPR4,
371 RegTypeStructByVal,
372 RegTypeStructByValInFP,
373 RegTypeStructByAddr,
374 RegTypeStructByAddrOnStack
375 } ArgStorage;
377 typedef struct {
378 gint32 offset; /* offset from caller's stack */
379 gint32 offparm; /* offset from callee's stack */
380 guint16 vtsize; /* in param area */
381 guint8 reg;
382 ArgStorage regtype;
383 guint32 size; /* Size of structure used by RegTypeStructByVal */
384 gint32 type; /* Data type of argument */
385 } ArgInfo;
387 struct CallInfo {
388 int nargs;
389 int lastgr;
390 guint32 stack_usage;
391 guint32 struct_ret;
392 ArgInfo ret;
393 ArgInfo sigCookie;
394 size_data sz;
395 int vret_arg_index;
396 MonoMethodSignature *sig;
397 ArgInfo args [1];
400 typedef struct {
401 gint64 gr[5]; /* R2-R6 */
402 gdouble fp[3]; /* F0-F2 */
403 } __attribute__ ((__packed__)) RegParm;
405 typedef struct {
406 RR_Format basr;
407 RI_Format j;
408 void *pTrigger;
409 RXY_Format lg;
410 RXY_Format trigger;
411 } __attribute__ ((__packed__)) breakpoint_t;
413 /*========================= End of Typedefs ========================*/
415 /*------------------------------------------------------------------*/
416 /* P r o t o t y p e s */
417 /*------------------------------------------------------------------*/
419 static void indent (int);
420 static guint8 * backUpStackPtr(MonoCompile *, guint8 *);
421 static void add_general (guint *, size_data *, ArgInfo *);
422 static void add_stackParm (guint *, size_data *, ArgInfo *, gint);
423 static void add_float (guint *, size_data *, ArgInfo *, gboolean);
424 static CallInfo * get_call_info (MonoMemPool *, MonoMethodSignature *);
425 static guchar * emit_float_to_int (MonoCompile *, guchar *, int, int, int, gboolean);
426 static __inline__ void emit_unwind_regs(MonoCompile *, guint8 *, int, int, long);
427 static void compare_and_branch(MonoBasicBlock *, MonoInst *, int, gboolean);
429 /*========================= End of Prototypes ======================*/
431 /*------------------------------------------------------------------*/
432 /* G l o b a l V a r i a b l e s */
433 /*------------------------------------------------------------------*/
435 __thread int indent_level = 0;
436 __thread FILE *trFd = NULL;
437 int curThreadNo = 0;
440 * The code generated for sequence points reads from this location,
441 * which is made read-only when single stepping is enabled.
443 static gpointer ss_trigger_page;
446 * Enabled breakpoints read from this trigger page
448 static gpointer bp_trigger_page;
450 breakpoint_t breakpointCode;
452 static const char * grNames[] = {
453 "s390_r0", "s390_sp", "s390_r2", "s390_r3", "s390_r4",
454 "s390_r5", "s390_r6", "s390_r7", "s390_r8", "s390_r9",
455 "s390_r10", "s390_r11", "s390_r12", "s390_r13", "s390_r14",
456 "s390_r15"
459 static const char * fpNames[] = {
460 "s390_f0", "s390_f1", "s390_f2", "s390_f3", "s390_f4",
461 "s390_f5", "s390_f6", "s390_f7", "s390_f8", "s390_f9",
462 "s390_f10", "s390_f11", "s390_f12", "s390_f13", "s390_f14",
463 "s390_f15"
466 static const char * vrNames[] = {
467 "vr0", "vr1", "vr2", "vr3", "vr4", "vr5", "vr6", "vr7",
468 "vr8", "vr9", "vr10", "vr11", "vr12", "vr13", "vr14", "vr15",
469 "vr16", "vr17", "vr18", "vr19", "vr20", "vr21", "vr22", "vr23",
470 "vr24", "vr25", "vr26", "vr27", "vr28", "vr29", "vr30", "vr31"
473 /*====================== End of Global Variables ===================*/
475 /*------------------------------------------------------------------*/
476 /* */
477 /* Name - mono_arch_regname */
478 /* */
479 /* Function - Returns the name of the register specified by */
480 /* the input parameter. */
481 /* */
482 /*------------------------------------------------------------------*/
484 const char*
485 mono_arch_regname (int reg)
487 if (reg >= 0 && reg < 16)
488 return grNames [reg];
489 else
490 return "unknown";
493 /*========================= End of Function ========================*/
495 /*------------------------------------------------------------------*/
496 /* */
497 /* Name - mono_arch_fregname */
498 /* */
499 /* Function - Returns the name of the register specified by */
500 /* the input parameter. */
501 /* */
502 /*------------------------------------------------------------------*/
504 const char*
505 mono_arch_fregname (int reg)
507 if (reg >= 0 && reg < 16)
508 return fpNames [reg];
509 else
510 return "unknown";
513 /*========================= End of Function ========================*/
515 /*------------------------------------------------------------------*/
516 /* */
517 /* Name - mono_arch_xregname */
518 /* */
519 /* Function - Returns the name of the register specified by */
520 /* the input parameter. */
521 /* */
522 /*------------------------------------------------------------------*/
524 const char *
525 mono_arch_xregname (int reg)
527 if (reg < s390_VR_NREG)
528 return vrNames [reg];
529 else
530 return "unknown";
533 /*========================= End of Function ========================*/
535 /*------------------------------------------------------------------*/
536 /* */
537 /* Name - arch_get_argument_info */
538 /* */
539 /* Function - Gathers information on parameters such as size, */
540 /* alignment, and padding. arg_info should be large */
541 /* enough to hold param_count + 1 entries. */
542 /* */
543 /* Parameters - @csig - Method signature */
544 /* @param_count - No. of parameters to consider */
545 /* @arg_info - An array to store the result info */
546 /* */
547 /* Returns - Size of the activation frame */
548 /* */
549 /*------------------------------------------------------------------*/
552 mono_arch_get_argument_info (MonoMethodSignature *csig,
553 int param_count,
554 MonoJitArgumentInfo *arg_info)
556 int k, frame_size = 0;
557 int size, align, pad;
558 int offset = 8;
560 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
561 frame_size += sizeof (target_mgreg_t);
562 offset += 8;
565 arg_info [0].offset = offset;
567 if (csig->hasthis) {
568 frame_size += sizeof (target_mgreg_t);
569 offset += 8;
572 arg_info [0].size = frame_size;
574 for (k = 0; k < param_count; k++) {
576 if (csig->pinvoke)
577 size = mono_type_native_stack_size (csig->params [k], (guint32 *) &align);
578 else
579 size = mini_type_stack_size (csig->params [k], &align);
581 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
582 arg_info [k].pad = pad;
583 frame_size += size;
584 arg_info [k + 1].pad = 0;
585 arg_info [k + 1].size = size;
586 offset += pad;
587 arg_info [k + 1].offset = offset;
588 offset += size;
591 align = MONO_ARCH_FRAME_ALIGNMENT;
592 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
593 arg_info [k].pad = pad;
595 return frame_size;
598 /*========================= End of Function ========================*/
600 /*------------------------------------------------------------------*/
601 /* */
602 /* Name - emit_unwind_regs. */
603 /* */
604 /* Function - Emit unwind information for a range of registers. */
605 /* */
606 /*------------------------------------------------------------------*/
608 static void __inline__
609 emit_unwind_regs(MonoCompile *cfg, guint8 *code, int start, int end, long offset)
611 int i;
613 for (i = start; i < end; i++) {
614 mono_emit_unwind_op_offset (cfg, code, i, offset);
615 mini_gc_set_slot_type_from_cfa (cfg, offset, SLOT_NOREF);
616 offset += sizeof(gulong);
620 /*========================= End of Function ========================*/
622 /*------------------------------------------------------------------*/
623 /* */
624 /* Name - retFitsInReg. */
625 /* */
626 /* Function - Determines if a value can be returned in one or */
627 /* two registers. */
628 /* */
629 /*------------------------------------------------------------------*/
631 static gboolean
632 retFitsInReg(guint32 size)
634 switch (size) {
635 case 0:
636 case 1:
637 case 2:
638 case 4:
639 case 8:
640 return (TRUE);
641 break;
642 default:
643 return (FALSE);
647 /*========================= End of Function ========================*/
649 /*------------------------------------------------------------------*/
650 /* */
651 /* Name - backStackPtr. */
652 /* */
653 /* Function - Restore Stack Pointer to previous frame. */
654 /* */
655 /*------------------------------------------------------------------*/
657 static guint8 *
658 backUpStackPtr(MonoCompile *cfg, guint8 *code)
660 int stackSize = cfg->stack_usage;
662 if (cfg->flags & MONO_CFG_HAS_ALLOCA) {
663 s390_lg (code, STK_BASE, 0, STK_BASE, 0);
664 } else {
665 if (cfg->frame_reg != STK_BASE)
666 s390_lgr (code, STK_BASE, cfg->frame_reg);
668 if (s390_is_imm16 (stackSize)) {
669 s390_aghi (code, STK_BASE, stackSize);
670 } else {
671 while (stackSize > 32767) {
672 s390_aghi (code, STK_BASE, 32767);
673 stackSize -= 32767;
675 s390_aghi (code, STK_BASE, stackSize);
679 return (code);
682 /*========================= End of Function ========================*/
684 /*------------------------------------------------------------------*/
685 /* */
686 /* Name - indent */
687 /* */
688 /* Function - Perform nice indenting to current level */
689 /* */
690 /*------------------------------------------------------------------*/
692 static void
693 indent (int diff) {
694 int v;
695 if (diff < 0)
696 indent_level += diff;
697 v = indent_level;
698 fprintf (trFd, "%p [%3d] ",(void *)pthread_self(),v);
699 while (v-- > 0) {
700 fprintf (trFd, ". ");
702 if (diff > 0)
703 indent_level += diff;
706 /*========================= End of Function ========================*/
708 /*------------------------------------------------------------------*/
709 /* */
710 /* Name - cvtMonoType */
711 /* */
712 /* Function - Convert a mono-type to a string. */
713 /* */
714 /*------------------------------------------------------------------*/
716 static const char *
717 cvtMonoType(MonoTypeEnum t)
719 switch(t)
721 case MONO_TYPE_END:
722 return "MONO_TYPE_END";
723 case MONO_TYPE_VOID:
724 return "MONO_TYPE_VOID";
725 case MONO_TYPE_BOOLEAN:
726 return "MONO_TYPE_BOOLEAN";
727 case MONO_TYPE_CHAR:
728 return "MONO_TYPE_CHAR";
729 case MONO_TYPE_I1:
730 return "MONO_TYPE_I1";
731 case MONO_TYPE_U1:
732 return "MONO_TYPE_U1";
733 case MONO_TYPE_I2:
734 return "MONO_TYPE_I2";
735 case MONO_TYPE_U2:
736 return "MONO_TYPE_U2";
737 case MONO_TYPE_I4:
738 return "MONO_TYPE_I4";
739 case MONO_TYPE_U4:
740 return "MONO_TYPE_U4";
741 case MONO_TYPE_I8:
742 return "MONO_TYPE_I8";
743 case MONO_TYPE_U8:
744 return "MONO_TYPE_U8";
745 case MONO_TYPE_R4:
746 return "MONO_TYPE_R4";
747 case MONO_TYPE_R8:
748 return "MONO_TYPE_R8";
749 case MONO_TYPE_STRING:
750 return "MONO_TYPE_STRING";
751 case MONO_TYPE_PTR:
752 return "MONO_TYPE_PTR";
753 case MONO_TYPE_BYREF:
754 return "MONO_TYPE_BYREF";
755 case MONO_TYPE_VALUETYPE:
756 return "MONO_TYPE_VALUETYPE";
757 case MONO_TYPE_CLASS:
758 return "MONO_TYPE_CLASS";
759 case MONO_TYPE_VAR:
760 return "MONO_TYPE_VAR";
761 case MONO_TYPE_ARRAY:
762 return "MONO_TYPE_ARRAY";
763 case MONO_TYPE_GENERICINST:
764 return "MONO_TYPE_GENERICINST";
765 case MONO_TYPE_TYPEDBYREF:
766 return "MONO_TYPE_TYPEDBYREF";
767 case MONO_TYPE_I:
768 return "MONO_TYPE_I";
769 case MONO_TYPE_U:
770 return "MONO_TYPE_U";
771 case MONO_TYPE_FNPTR:
772 return "MONO_TYPE_FNPTR";
773 case MONO_TYPE_OBJECT:
774 return "MONO_TYPE_OBJECT";
775 case MONO_TYPE_SZARRAY:
776 return "MONO_TYPE_SZARRAY";
777 case MONO_TYPE_MVAR:
778 return "MONO_TYPE_MVAR";
779 case MONO_TYPE_CMOD_REQD:
780 return "MONO_TYPE_CMOD_REQD";
781 case MONO_TYPE_CMOD_OPT:
782 return "MONO_TYPE_CMOD_OPT";
783 case MONO_TYPE_INTERNAL:
784 return "MONO_TYPE_INTERNAL";
785 case MONO_TYPE_MODIFIER:
786 return "MONO_TYPE_MODIFIER";
787 case MONO_TYPE_SENTINEL:
788 return "MONO_TYPE_SENTINEL";
789 case MONO_TYPE_PINNED:
790 return "MONO_TYPE_PINNED";
791 default:
794 return "unknown";
797 /*========================= End of Function ========================*/
799 /*------------------------------------------------------------------*/
800 /* */
801 /* Name - mono_arch_cpu_init */
802 /* */
803 /* Function - Perform CPU specific initialization to execute */
804 /* managed code. */
805 /* */
806 /*------------------------------------------------------------------*/
808 void
809 mono_arch_cpu_init (void)
813 /*========================= End of Function ========================*/
815 /*------------------------------------------------------------------*/
816 /* */
817 /* Name - mono_arch_init. */
818 /* */
819 /* Function - Initialize architecture specific code. */
820 /* */
821 /*------------------------------------------------------------------*/
823 void
824 mono_arch_init (void)
826 guint8 *code;
828 mono_set_partial_sharing_supported (FALSE);
830 ss_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ, MONO_MEM_ACCOUNT_OTHER);
831 bp_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ, MONO_MEM_ACCOUNT_OTHER);
832 mono_mprotect (bp_trigger_page, mono_pagesize (), 0);
834 code = (guint8 *) &breakpointCode;
835 s390_basr(code, s390_r13, 0);
836 s390_j(code, 6);
837 s390_llong(code, 0);
838 s390_lg(code, s390_r13, 0, s390_r13, 4);
839 s390_lg(code, s390_r0, 0, s390_r13, 0);
842 /*========================= End of Function ========================*/
844 /*------------------------------------------------------------------*/
845 /* */
846 /* Name - mono_arch_cleanup. */
847 /* */
848 /* Function - Cleanup architecture specific code . */
849 /* */
850 /*------------------------------------------------------------------*/
852 void
853 mono_arch_cleanup (void)
855 if (ss_trigger_page)
856 mono_vfree (ss_trigger_page, mono_pagesize (), MONO_MEM_ACCOUNT_OTHER);
857 if (bp_trigger_page)
858 mono_vfree (bp_trigger_page, mono_pagesize (), MONO_MEM_ACCOUNT_OTHER);
861 /*========================= End of Function ========================*/
863 /*------------------------------------------------------------------*/
864 /* */
865 /* Name - mono_arch_have_fast_tls */
866 /* */
867 /* Function - Returns whether we use fast inlined thread local */
868 /* storage managed access, instead of falling back */
869 /* to native code. */
870 /* */
871 /*------------------------------------------------------------------*/
873 gboolean
874 mono_arch_have_fast_tls (void)
876 return TRUE;
879 /*========================= End of Function ========================*/
881 /*------------------------------------------------------------------*/
882 /* */
883 /* Name - mono_arch_cpu_optimizations */
884 /* */
885 /* Function - Returns the optimizations supported on this CPU */
886 /* */
887 /*------------------------------------------------------------------*/
889 guint32
890 mono_arch_cpu_optimizations (guint32 *exclude_mask)
892 guint32 opts = 0;
894 /*----------------------------------------------------------*/
895 /* No s390-specific optimizations yet */
896 /*----------------------------------------------------------*/
897 *exclude_mask = MONO_OPT_LINEARS;
898 return opts;
901 /*========================= End of Function ========================*/
903 /*------------------------------------------------------------------*/
904 /* */
905 /* Name - mono_arch_get_allocatable_int_vars */
906 /* */
907 /* Function - */
908 /* */
909 /*------------------------------------------------------------------*/
911 GList *
912 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
914 GList *vars = NULL;
915 int i;
917 for (i = 0; i < cfg->num_varinfo; i++) {
918 MonoInst *ins = cfg->varinfo [i];
919 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
921 /* unused vars */
922 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
923 continue;
925 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) ||
926 (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
927 continue;
929 /* we can only allocate 32 bit values */
930 if (mono_is_regsize_var(ins->inst_vtype)) {
931 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
932 g_assert (i == vmv->idx);
933 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
937 return vars;
940 /*========================= End of Function ========================*/
942 /*------------------------------------------------------------------*/
943 /* */
944 /* Name - mono_arch_global_int_regs */
945 /* */
946 /* Function - Return a list of usable integer registers. */
947 /* */
948 /*------------------------------------------------------------------*/
950 GList *
951 mono_arch_get_global_int_regs (MonoCompile *cfg)
953 GList *regs = NULL;
954 MonoMethodHeader *header;
955 int i, top = 13;
957 header = cfg->header;
958 if ((cfg->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses)
959 cfg->frame_reg = s390_r11;
962 /* FIXME: s390_r12 is reserved for bkchain_reg. Only reserve it if needed */
963 top = 12;
964 for (i = 8; i < top; ++i) {
965 if ((cfg->frame_reg != i) &&
966 //!((cfg->uses_rgctx_reg) && (i == MONO_ARCH_IMT_REG)))
967 (i != MONO_ARCH_IMT_REG))
968 regs = g_list_prepend (regs, GUINT_TO_POINTER (i));
971 return regs;
974 /*========================= End of Function ========================*/
976 /*------------------------------------------------------------------*/
977 /* */
978 /* Name - mono_arch_flush_icache */
979 /* */
980 /* Function - Flush the CPU icache. */
981 /* */
982 /*------------------------------------------------------------------*/
984 void
985 mono_arch_flush_icache (guint8 *code, gint size)
989 /*========================= End of Function ========================*/
991 /*------------------------------------------------------------------*/
992 /* */
993 /* Name - add_general */
994 /* */
995 /* Function - Determine code and stack size incremements for a */
996 /* parameter. */
997 /* */
998 /*------------------------------------------------------------------*/
1000 static void inline
1001 add_general (guint *gr, size_data *sz, ArgInfo *ainfo)
1003 if (*gr > S390_LAST_ARG_REG) {
1004 sz->stack_size = S390_ALIGN(sz->stack_size, sizeof(long));
1005 ainfo->offset = sz->stack_size;
1006 ainfo->reg = STK_BASE;
1007 ainfo->regtype = RegTypeBase;
1008 sz->stack_size += sizeof(long);
1009 sz->local_size += sizeof(long);
1010 sz->offStruct += sizeof(long);
1011 sz->code_size += 12;
1012 } else {
1013 ainfo->reg = *gr;
1014 sz->code_size += 8;
1016 (*gr) ++;
1019 /*========================= End of Function ========================*/
1021 /*------------------------------------------------------------------*/
1022 /* */
1023 /* Name - add_stackParm */
1024 /* */
1025 /* Function - Determine code and stack size incremements for a */
1026 /* parameter. */
1027 /* */
1028 /*------------------------------------------------------------------*/
1030 static void inline
1031 add_stackParm (guint *gr, size_data *sz, ArgInfo *ainfo, gint size)
1033 if (*gr > S390_LAST_ARG_REG) {
1034 sz->stack_size = S390_ALIGN(sz->stack_size, sizeof(long));
1035 ainfo->reg = STK_BASE;
1036 ainfo->offset = sz->stack_size;
1037 ainfo->regtype = RegTypeStructByAddrOnStack;
1038 sz->stack_size += sizeof (target_mgreg_t);
1039 sz->parm_size += sizeof(gpointer);
1040 sz->offStruct += sizeof(gpointer);
1041 } else {
1042 ainfo->reg = *gr;
1043 ainfo->offset = sz->stack_size;
1044 ainfo->regtype = RegTypeStructByAddr;
1046 (*gr) ++;
1047 ainfo->offparm = sz->offset;
1048 sz->offset = S390_ALIGN(sz->offset+size, sizeof(long));
1049 ainfo->size = size;
1050 ainfo->vtsize = size;
1051 sz->parm_size += size;
1054 /*========================= End of Function ========================*/
1056 /*------------------------------------------------------------------*/
1057 /* */
1058 /* Name - add_float */
1059 /* */
1060 /* Function - Determine code and stack size incremements for a */
1061 /* float parameter. */
1062 /* */
1063 /*------------------------------------------------------------------*/
1065 static void inline
1066 add_float (guint *fr, size_data *sz, ArgInfo *ainfo, gboolean isDouble)
1068 if ((*fr) <= S390_LAST_FPARG_REG) {
1069 if (isDouble)
1070 ainfo->regtype = RegTypeFP;
1071 else
1072 ainfo->regtype = RegTypeFPR4;
1073 ainfo->reg = *fr;
1074 sz->code_size += 4;
1075 (*fr) += 2;
1077 else {
1078 ainfo->offset = sz->stack_size;
1079 ainfo->reg = STK_BASE;
1080 sz->code_size += 4;
1081 sz->stack_size += sizeof(double);
1082 sz->local_size += sizeof(double);
1083 sz->offStruct += sizeof(double);
1084 ainfo->regtype = RegTypeBase;
1088 /*========================= End of Function ========================*/
1090 /*------------------------------------------------------------------*/
1091 /* */
1092 /* Name - get_call_info */
1093 /* */
1094 /* Function - Determine the amount of space required for code */
1095 /* and stack. In addition determine starting points */
1096 /* for stack-based parameters, and area for struct- */
1097 /* ures being returned on the stack. */
1098 /* */
1099 /*------------------------------------------------------------------*/
1101 static CallInfo *
1102 get_call_info (MonoMemPool *mp, MonoMethodSignature *sig)
1104 guint i, fr, gr, size, pstart;
1105 int nParm = sig->hasthis + sig->param_count;
1106 MonoType *ret_type;
1107 guint32 simpleType, align;
1108 gboolean is_pinvoke = sig->pinvoke;
1109 CallInfo *cinfo;
1110 size_data *sz;
1112 if (mp)
1113 cinfo = mono_mempool_alloc0 (mp, sizeof (CallInfo) + sizeof (ArgInfo) * nParm);
1114 else
1115 cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * nParm);
1117 fr = 0;
1118 gr = s390_r2;
1119 nParm = 0;
1120 cinfo->struct_ret = 0;
1121 cinfo->sig = sig;
1122 sz = &cinfo->sz;
1123 sz->retStruct = 0;
1124 sz->offset = 0;
1125 sz->offStruct = S390_MINIMAL_STACK_SIZE;
1126 sz->stack_size = S390_MINIMAL_STACK_SIZE;
1127 sz->code_size = 0;
1128 sz->parm_size = 0;
1129 sz->local_size = 0;
1130 align = 0;
1131 size = 0;
1133 /*----------------------------------------------------------*/
1134 /* We determine the size of the return code/stack in case we*/
1135 /* need to reserve a register to be used to address a stack */
1136 /* area that the callee will use. */
1137 /*----------------------------------------------------------*/
1139 ret_type = mini_get_underlying_type (sig->ret);
1140 simpleType = ret_type->type;
1141 enum_retvalue:
1142 switch (simpleType) {
1143 case MONO_TYPE_I1:
1144 case MONO_TYPE_U1:
1145 case MONO_TYPE_I2:
1146 case MONO_TYPE_U2:
1147 case MONO_TYPE_I4:
1148 case MONO_TYPE_U4:
1149 case MONO_TYPE_I:
1150 case MONO_TYPE_U:
1151 case MONO_TYPE_OBJECT:
1152 case MONO_TYPE_PTR:
1153 case MONO_TYPE_FNPTR:
1154 cinfo->ret.reg = s390_r2;
1155 sz->code_size += 4;
1156 break;
1157 case MONO_TYPE_R4:
1158 case MONO_TYPE_R8:
1159 cinfo->ret.reg = s390_f0;
1160 sz->code_size += 4;
1161 break;
1162 case MONO_TYPE_I8:
1163 case MONO_TYPE_U8:
1164 cinfo->ret.reg = s390_r2;
1165 sz->code_size += 4;
1166 break;
1167 case MONO_TYPE_GENERICINST:
1168 if (!mono_type_generic_inst_is_valuetype (sig->ret)) {
1169 cinfo->ret.reg = s390_r2;
1170 sz->code_size += 4;
1171 break;
1173 /* Fall through */
1174 case MONO_TYPE_VALUETYPE: {
1175 MonoClass *klass = mono_class_from_mono_type_internal (sig->ret);
1176 if (m_class_is_enumtype (klass)) {
1177 simpleType = mono_class_enum_basetype_internal (klass)->type;
1178 goto enum_retvalue;
1180 size = mini_type_stack_size_full (m_class_get_byval_arg (klass), NULL, sig->pinvoke);
1182 cinfo->struct_ret = 1;
1183 cinfo->ret.size = size;
1184 cinfo->ret.vtsize = size;
1185 break;
1187 case MONO_TYPE_TYPEDBYREF:
1188 size = MONO_ABI_SIZEOF (MonoTypedRef);
1189 cinfo->struct_ret = 1;
1190 cinfo->ret.size = size;
1191 cinfo->ret.vtsize = size;
1192 break;
1193 case MONO_TYPE_VOID:
1194 break;
1195 default:
1196 g_error ("Can't handle as return value 0x%x", sig->ret->type);
1200 pstart = 0;
1202 * To simplify get_this_arg_reg () and LLVM integration, emit the vret arg after
1203 * the first argument, allowing 'this' to be always passed in the first arg reg.
1204 * Also do this if the first argument is a reference type, since virtual calls
1205 * are sometimes made using calli without sig->hasthis set, like in the delegate
1206 * invoke wrappers.
1208 if (cinfo->struct_ret && !is_pinvoke &&
1209 (sig->hasthis ||
1210 (sig->param_count > 0 &&
1211 MONO_TYPE_IS_REFERENCE (mini_get_underlying_type (sig->params [0]))))) {
1212 if (sig->hasthis) {
1213 cinfo->args[nParm].size = sizeof (target_mgreg_t);
1214 add_general (&gr, sz, cinfo->args + nParm);
1215 } else {
1216 cinfo->args[nParm].size = sizeof (target_mgreg_t);
1217 add_general (&gr, sz, &cinfo->args [sig->hasthis + nParm]);
1218 pstart = 1;
1220 nParm ++;
1221 cinfo->vret_arg_index = 1;
1222 cinfo->ret.reg = gr;
1223 gr ++;
1224 } else {
1225 /* this */
1226 if (sig->hasthis) {
1227 cinfo->args[nParm].size = sizeof (target_mgreg_t);
1228 add_general (&gr, sz, cinfo->args + nParm);
1229 nParm ++;
1232 if (cinfo->struct_ret) {
1233 cinfo->ret.reg = gr;
1234 gr ++;
1238 if ((sig->call_convention == MONO_CALL_VARARG) && (sig->param_count == 0)) {
1239 gr = S390_LAST_ARG_REG + 1;
1240 fr = S390_LAST_FPARG_REG + 1;
1242 /* Emit the signature cookie just before the implicit arguments */
1243 add_general (&gr, sz, &cinfo->sigCookie);
1246 /*----------------------------------------------------------*/
1247 /* We determine the size of the parameter code and stack */
1248 /* requirements by checking the types and sizes of the */
1249 /* parameters. */
1250 /*----------------------------------------------------------*/
1252 for (i = pstart; i < sig->param_count; ++i) {
1253 MonoType *ptype;
1255 /*--------------------------------------------------*/
1256 /* Handle vararg type calls. All args are put on */
1257 /* the stack. */
1258 /*--------------------------------------------------*/
1259 if ((sig->call_convention == MONO_CALL_VARARG) &&
1260 (i == sig->sentinelpos)) {
1261 gr = S390_LAST_ARG_REG + 1;
1262 fr = S390_LAST_FPARG_REG + 1;
1263 add_general (&gr, sz, &cinfo->sigCookie);
1266 if (sig->params [i]->byref) {
1267 add_general (&gr, sz, cinfo->args+nParm);
1268 cinfo->args[nParm].size = sizeof(gpointer);
1269 nParm++;
1270 continue;
1273 ptype = mini_get_underlying_type (sig->params [i]);
1274 simpleType = ptype->type;
1275 cinfo->args[nParm].type = simpleType;
1276 switch (simpleType) {
1277 case MONO_TYPE_I1:
1278 case MONO_TYPE_U1:
1279 cinfo->args[nParm].size = sizeof(char);
1280 add_general (&gr, sz, cinfo->args+nParm);
1281 nParm++;
1282 break;
1283 case MONO_TYPE_I2:
1284 case MONO_TYPE_U2:
1285 cinfo->args[nParm].size = sizeof(short);
1286 add_general (&gr, sz, cinfo->args+nParm);
1287 nParm++;
1288 break;
1289 case MONO_TYPE_I4:
1290 case MONO_TYPE_U4:
1291 cinfo->args[nParm].size = sizeof(int);
1292 add_general (&gr, sz, cinfo->args+nParm);
1293 nParm++;
1294 break;
1295 case MONO_TYPE_I:
1296 case MONO_TYPE_U:
1297 case MONO_TYPE_PTR:
1298 case MONO_TYPE_FNPTR:
1299 case MONO_TYPE_OBJECT:
1300 cinfo->args[nParm].size = sizeof(gpointer);
1301 add_general (&gr, sz, cinfo->args+nParm);
1302 nParm++;
1303 break;
1304 case MONO_TYPE_I8:
1305 case MONO_TYPE_U8:
1306 cinfo->args[nParm].size = sizeof(long long);
1307 add_general (&gr, sz, cinfo->args+nParm);
1308 nParm++;
1309 break;
1310 case MONO_TYPE_R4:
1311 cinfo->args[nParm].size = sizeof(float);
1312 add_float (&fr, sz, cinfo->args+nParm, FALSE);
1313 nParm++;
1314 break;
1315 case MONO_TYPE_R8:
1316 cinfo->args[nParm].size = sizeof(double);
1317 add_float (&fr, sz, cinfo->args+nParm, TRUE);
1318 nParm++;
1319 break;
1320 case MONO_TYPE_GENERICINST:
1321 if (!mono_type_generic_inst_is_valuetype (ptype)) {
1322 cinfo->args[nParm].size = sizeof(gpointer);
1323 add_general (&gr, sz, cinfo->args+nParm);
1324 nParm++;
1325 break;
1327 /* Fall through */
1328 case MONO_TYPE_VALUETYPE: {
1329 MonoMarshalType *info;
1330 MonoClass *klass = mono_class_from_mono_type_internal (ptype);
1332 if (sig->pinvoke)
1333 size = mono_class_native_size(klass, NULL);
1334 else
1335 size = mono_class_value_size(klass, NULL);
1337 if (simpleType != MONO_TYPE_GENERICINST) {
1338 info = mono_marshal_load_type_info(klass);
1340 if ((info->native_size == sizeof(float)) &&
1341 (info->num_fields == 1) &&
1342 (info->fields[0].field->type->type == MONO_TYPE_R4)) {
1343 cinfo->args[nParm].size = sizeof(float);
1344 add_float(&fr, sz, cinfo->args+nParm, FALSE);
1345 nParm ++;
1346 break;
1349 if ((info->native_size == sizeof(double)) &&
1350 (info->num_fields == 1) &&
1351 (info->fields[0].field->type->type == MONO_TYPE_R8)) {
1352 cinfo->args[nParm].size = sizeof(double);
1353 add_float(&fr, sz, cinfo->args+nParm, TRUE);
1354 nParm ++;
1355 break;
1359 cinfo->args[nParm].vtsize = 0;
1360 cinfo->args[nParm].size = 0;
1362 switch (size) {
1363 /*----------------------------------*/
1364 /* On S/390, structures of size 1, */
1365 /* 2, 4, and 8 bytes are passed in */
1366 /* (a) register(s). */
1367 /*----------------------------------*/
1368 case 0:
1369 case 1:
1370 case 2:
1371 case 4:
1372 case 8:
1373 add_general(&gr, sz, cinfo->args+nParm);
1374 cinfo->args[nParm].size = size;
1375 cinfo->args[nParm].regtype = RegTypeStructByVal;
1376 nParm++;
1377 sz->local_size += sizeof(long);
1378 break;
1379 default:
1380 add_stackParm(&gr, sz, cinfo->args+nParm, size);
1381 nParm++;
1384 break;
1385 case MONO_TYPE_TYPEDBYREF: {
1386 int size = MONO_ABI_SIZEOF (MonoTypedRef);
1388 cinfo->args[nParm].vtsize = 0;
1389 cinfo->args[nParm].size = 0;
1391 switch (size) {
1392 /*----------------------------------*/
1393 /* On S/390, structures of size 1, */
1394 /* 2, 4, and 8 bytes are passed in */
1395 /* (a) register(s). */
1396 /*----------------------------------*/
1397 case 0:
1398 case 1:
1399 case 2:
1400 case 4:
1401 case 8:
1402 add_general(&gr, sz, cinfo->args+nParm);
1403 cinfo->args[nParm].size = size;
1404 cinfo->args[nParm].regtype = RegTypeStructByVal;
1405 nParm++;
1406 sz->local_size += sizeof(long);
1407 break;
1408 default:
1409 add_stackParm(&gr, sz, cinfo->args+nParm, size);
1410 nParm++;
1413 break;
1414 default:
1415 g_error ("Can't trampoline 0x%x", ptype);
1419 /*----------------------------------------------------------*/
1420 /* Handle the case where there are no implicit arguments */
1421 /*----------------------------------------------------------*/
1422 if ((sig->call_convention == MONO_CALL_VARARG) &&
1423 (nParm > 0) &&
1424 (!sig->pinvoke) &&
1425 (sig->param_count == sig->sentinelpos)) {
1426 gr = S390_LAST_ARG_REG + 1;
1427 fr = S390_LAST_FPARG_REG + 1;
1428 add_general (&gr, sz, &cinfo->sigCookie);
1431 /*----------------------------------------------------------*/
1432 /* If we are passing a structure back then if it won't be */
1433 /* in a register(s) then we make room at the end of the */
1434 /* parameters that may have been placed on the stack */
1435 /*----------------------------------------------------------*/
1436 if (cinfo->struct_ret) {
1437 cinfo->ret.offset = sz->stack_size;
1438 switch (cinfo->ret.size) {
1439 case 0:
1440 case 1:
1441 case 2:
1442 case 4:
1443 case 8:
1444 break;
1445 default:
1446 sz->stack_size += S390_ALIGN(cinfo->ret.size, align);
1450 cinfo->lastgr = gr;
1451 sz->stack_size = sz->stack_size + sz->local_size + sz->parm_size +
1452 sz->offset;
1453 sz->stack_size = S390_ALIGN(sz->stack_size, sizeof(long));
1455 return (cinfo);
1458 /*========================= End of Function ========================*/
1460 /*------------------------------------------------------------------*/
1461 /* */
1462 /* Name - mono_arch_allocate_vars */
1463 /* */
1464 /* Function - Set var information according to the calling */
1465 /* convention for S/390. The local var stuff should */
1466 /* most likely be split in another method. */
1467 /* */
1468 /* Parameter - @m - Compile unit. */
1469 /* */
1470 /*------------------------------------------------------------------*/
1472 void
1473 mono_arch_allocate_vars (MonoCompile *cfg)
1475 MonoMethodSignature *sig;
1476 MonoMethodHeader *header;
1477 MonoInst *inst;
1478 CallInfo *cinfo;
1479 int iParm, iVar, offset, align, size, curinst;
1480 int frame_reg = STK_BASE;
1481 int sArg, eArg;
1483 header = cfg->header;
1485 cfg->flags |= MONO_CFG_HAS_SPILLUP;
1487 /*---------------------------------------------------------*/
1488 /* We use the frame register also for any method that has */
1489 /* filter clauses. This way, when the handlers are called, */
1490 /* the code will reference local variables using the frame */
1491 /* reg instead of the stack pointer: if we had to restore */
1492 /* the stack pointer, we'd corrupt the method frames that */
1493 /* are already on the stack (since filters get called */
1494 /* before stack unwinding happens) when the filter code */
1495 /* would call any method. */
1496 /*---------------------------------------------------------*/
1497 if ((cfg->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses)
1498 frame_reg = s390_r11;
1500 cfg->frame_reg = frame_reg;
1502 cfg->arch.bkchain_reg = -1;
1504 if (frame_reg != STK_BASE)
1505 cfg->used_int_regs |= (1LL << frame_reg);
1507 sig = mono_method_signature_internal (cfg->method);
1509 cinfo = get_call_info (cfg->mempool, sig);
1511 if (!cinfo->struct_ret) {
1512 switch (mini_get_underlying_type (sig->ret)->type) {
1513 case MONO_TYPE_VOID:
1514 break;
1515 default:
1516 cfg->ret->opcode = OP_REGVAR;
1517 cfg->ret->dreg = s390_r2;
1518 break;
1522 /*--------------------------------------------------------------*/
1523 /* local vars are at a positive offset from the stack pointer */
1524 /* also note that if the function uses alloca, we use s390_r11 */
1525 /* to point at the local variables. */
1526 /* add parameter area size for called functions */
1527 /*--------------------------------------------------------------*/
1528 if (cfg->param_area == 0)
1529 offset = S390_MINIMAL_STACK_SIZE;
1530 else
1531 offset = cfg->param_area;
1533 cfg->sig_cookie = 0;
1535 if (cinfo->struct_ret) {
1536 inst = cfg->vret_addr;
1537 offset = S390_ALIGN(offset, sizeof(gpointer));
1538 inst->inst_offset = offset;
1539 inst->opcode = OP_REGOFFSET;
1540 inst->inst_basereg = frame_reg;
1541 offset += sizeof(gpointer);
1542 if (G_UNLIKELY (cfg->verbose_level > 1)) {
1543 printf ("vret_addr =");
1544 mono_print_ins (cfg->vret_addr);
1548 if (sig->hasthis) {
1549 inst = cfg->args [0];
1550 if (inst->opcode != OP_REGVAR) {
1551 inst->opcode = OP_REGOFFSET;
1552 inst->inst_basereg = frame_reg;
1553 offset = S390_ALIGN(offset, sizeof(gpointer));
1554 inst->inst_offset = offset;
1555 offset += sizeof (target_mgreg_t);
1557 curinst = sArg = 1;
1558 } else {
1559 curinst = sArg = 0;
1562 eArg = sig->param_count + sArg;
1564 if (sig->call_convention == MONO_CALL_VARARG)
1565 cfg->sig_cookie += S390_MINIMAL_STACK_SIZE;
1567 for (iParm = sArg; iParm < eArg; ++iParm) {
1568 inst = cfg->args [curinst];
1569 if (inst->opcode != OP_REGVAR) {
1570 switch (cinfo->args[iParm].regtype) {
1571 case RegTypeStructByAddr : {
1572 MonoInst *indir;
1574 size = sizeof (target_mgreg_t);
1576 inst->opcode = OP_REGOFFSET;
1577 inst->inst_basereg = frame_reg;
1578 offset = S390_ALIGN (offset, sizeof (target_mgreg_t));
1579 inst->inst_offset = offset;
1581 /* Add a level of indirection */
1582 MONO_INST_NEW (cfg, indir, 0);
1583 *indir = *inst;
1584 inst->opcode = OP_VTARG_ADDR;
1585 inst->inst_left = indir;
1587 break;
1588 case RegTypeStructByAddrOnStack : {
1589 MonoInst *indir;
1591 size = sizeof (target_mgreg_t);
1593 /* Similar to the == STK_BASE case below */
1594 cfg->arch.bkchain_reg = s390_r12;
1595 cfg->used_int_regs |= 1 << cfg->arch.bkchain_reg;
1597 inst->opcode = OP_REGOFFSET;
1598 inst->dreg = mono_alloc_preg (cfg);
1599 inst->inst_basereg = cfg->arch.bkchain_reg;
1600 inst->inst_offset = cinfo->args [iParm].offset;
1602 /* Add a level of indirection */
1603 MONO_INST_NEW (cfg, indir, 0);
1604 *indir = *inst;
1605 inst->opcode = OP_VTARG_ADDR;
1606 inst->inst_left = indir;
1607 break;
1609 case RegTypeStructByVal :
1610 size = cinfo->args[iParm].size;
1611 offset = S390_ALIGN(offset, size);
1612 inst->opcode = OP_REGOFFSET;
1613 inst->inst_basereg = frame_reg;
1614 inst->inst_offset = offset;
1615 break;
1616 default :
1617 if (cinfo->args [iParm].reg == STK_BASE) {
1619 * These arguments are in the previous frame, so we can't
1620 * compute their offset from the current frame pointer right
1621 * now, since cfg->stack_offset is not yet known, so dedicate a
1622 * register holding the previous frame pointer.
1624 cfg->arch.bkchain_reg = s390_r12;
1625 cfg->used_int_regs |= 1 << cfg->arch.bkchain_reg;
1627 inst->opcode = OP_REGOFFSET;
1628 inst->inst_basereg = cfg->arch.bkchain_reg;
1629 size = (cinfo->args[iParm].size < 8
1630 ? 8 - cinfo->args[iParm].size
1631 : 0);
1632 inst->inst_offset = cinfo->args [iParm].offset + size;
1633 size = sizeof (long);
1634 } else {
1635 inst->opcode = OP_REGOFFSET;
1636 inst->inst_basereg = frame_reg;
1637 size = (cinfo->args[iParm].size < 8
1638 ? sizeof(int)
1639 : sizeof(long));
1640 offset = S390_ALIGN(offset, size);
1641 if (cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1642 inst->inst_offset = offset;
1643 else
1644 inst->inst_offset = offset + (8 - size);
1646 break;
1648 offset += MAX(size, 8);
1650 curinst++;
1653 cfg->locals_min_stack_offset = offset;
1655 curinst = cfg->locals_start;
1656 for (iVar = curinst; iVar < cfg->num_varinfo; ++iVar) {
1657 inst = cfg->varinfo [iVar];
1658 if ((inst->flags & MONO_INST_IS_DEAD) ||
1659 (inst->opcode == OP_REGVAR))
1660 continue;
1662 /*--------------------------------------------------*/
1663 /* inst->backend.is_pinvoke indicates native sized */
1664 /* value types this is used by the pinvoke wrappers */
1665 /* when they call functions returning structure */
1666 /*--------------------------------------------------*/
1667 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype))
1668 size = mono_class_native_size (mono_class_from_mono_type_internal (inst->inst_vtype),
1669 (guint32 *) &align);
1670 else
1671 size = mono_type_size (inst->inst_vtype, &align);
1673 offset = S390_ALIGN(offset, align);
1674 inst->inst_offset = offset;
1675 inst->opcode = OP_REGOFFSET;
1676 inst->inst_basereg = frame_reg;
1677 offset += size;
1678 DEBUG (g_print("allocating local %d to %ld, size: %d\n",
1679 iVar, inst->inst_offset, size));
1682 cfg->locals_max_stack_offset = offset;
1684 /*------------------------------------------------------*/
1685 /* Reserve space to save LMF and caller saved registers */
1686 /*------------------------------------------------------*/
1687 if (cfg->method->save_lmf)
1688 offset += sizeof (MonoLMF);
1690 /*------------------------------------------------------*/
1691 /* align the offset */
1692 /*------------------------------------------------------*/
1693 cfg->stack_offset = S390_ALIGN(offset, S390_STACK_ALIGNMENT);
1695 /*------------------------------------------------------*/
1696 /* Fix offsets for args whose value is in parent frame */
1697 /*------------------------------------------------------*/
1698 for (iParm = sArg; iParm < eArg; ++iParm) {
1699 inst = cfg->args [iParm];
1701 if (inst->opcode == OP_S390_STKARG) {
1702 inst->opcode = OP_REGOFFSET;
1703 inst->inst_offset += cfg->stack_offset;
1708 /*========================= End of Function ========================*/
1710 /*------------------------------------------------------------------*/
1711 /* */
1712 /* Name - mono_arch_create_vars */
1713 /* */
1714 /*------------------------------------------------------------------*/
1716 void
1717 mono_arch_create_vars (MonoCompile *cfg)
1719 MonoMethodSignature *sig;
1720 CallInfo *cinfo;
1722 sig = mono_method_signature_internal (cfg->method);
1724 cinfo = get_call_info (cfg->mempool, sig);
1726 if (cinfo->struct_ret) {
1727 cfg->vret_addr = mono_compile_create_var (cfg, mono_get_int_type (), OP_ARG);
1728 if (G_UNLIKELY (cfg->verbose_level > 1)) {
1729 printf ("vret_addr = ");
1730 mono_print_ins (cfg->vret_addr);
1735 /*========================= End of Function ========================*/
1737 /*------------------------------------------------------------------*/
1738 /* */
1739 /* Name - add_outarg_reg2. */
1740 /* */
1741 /*------------------------------------------------------------------*/
1743 static void
1744 add_outarg_reg2 (MonoCompile *cfg, MonoCallInst *call, ArgStorage storage, int reg, MonoInst *tree)
1746 MonoInst *ins;
1748 switch (storage) {
1749 case RegTypeGeneral:
1750 MONO_INST_NEW (cfg, ins, OP_MOVE);
1751 ins->dreg = mono_alloc_ireg (cfg);
1752 ins->sreg1 = tree->dreg;
1753 MONO_ADD_INS (cfg->cbb, ins);
1754 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, reg, FALSE);
1755 break;
1756 case RegTypeFP:
1757 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1758 ins->dreg = mono_alloc_freg (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, TRUE);
1762 break;
1763 case RegTypeFPR4:
1764 MONO_INST_NEW (cfg, ins, OP_S390_SETF4RET);
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 default:
1771 g_assert_not_reached ();
1775 /*========================= End of Function ========================*/
1777 /*------------------------------------------------------------------*/
1778 /* */
1779 /* Name - emit_sig_cookie. */
1780 /* */
1781 /*------------------------------------------------------------------*/
1783 static void
1784 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1786 MonoMethodSignature *tmpSig;
1787 MonoInst *sig_arg;
1789 cfg->disable_aot = TRUE;
1791 /*----------------------------------------------------------*/
1792 /* mono_ArgIterator_Setup assumes the signature cookie is */
1793 /* passed first and all the arguments which were before it */
1794 /* passed on the stack after the signature. So compensate */
1795 /* by passing a different signature. */
1796 /*----------------------------------------------------------*/
1797 tmpSig = mono_metadata_signature_dup (call->signature);
1798 tmpSig->param_count -= call->signature->sentinelpos;
1799 tmpSig->sentinelpos = 0;
1800 if (tmpSig->param_count > 0)
1801 memcpy (tmpSig->params,
1802 call->signature->params + call->signature->sentinelpos,
1803 tmpSig->param_count * sizeof(MonoType *));
1805 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
1806 sig_arg->dreg = mono_alloc_ireg (cfg);
1807 sig_arg->inst_p0 = tmpSig;
1808 MONO_ADD_INS (cfg->cbb, sig_arg);
1810 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, STK_BASE,
1811 cinfo->sigCookie.offset, sig_arg->dreg);
1814 /*========================= End of Function ========================*/
1816 /*------------------------------------------------------------------*/
1817 /* */
1818 /* Name - mono_arch_emit_call */
1819 /* */
1820 /*------------------------------------------------------------------*/
1822 void
1823 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1825 MonoInst *in;
1826 MonoMethodSignature *sig;
1827 MonoInst *ins;
1828 int i, n, lParamArea;
1829 CallInfo *cinfo;
1830 ArgInfo *ainfo = NULL;
1831 int stackSize;
1833 sig = call->signature;
1834 n = sig->param_count + sig->hasthis;
1835 DEBUG (g_print ("Call requires: %d parameters\n",n));
1837 cinfo = get_call_info (cfg->mempool, sig);
1839 stackSize = cinfo->sz.stack_size + cinfo->sz.local_size +
1840 cinfo->sz.parm_size + cinfo->sz.offset;
1841 call->stack_usage = MAX(stackSize, call->stack_usage);
1842 lParamArea = MAX((call->stack_usage-S390_MINIMAL_STACK_SIZE-cinfo->sz.parm_size), 0);
1843 cfg->param_area = MAX(((signed) cfg->param_area), lParamArea);
1844 cfg->flags |= MONO_CFG_HAS_CALLS;
1846 if (cinfo->struct_ret) {
1847 MONO_INST_NEW (cfg, ins, OP_MOVE);
1848 ins->sreg1 = call->vret_var->dreg;
1849 ins->dreg = mono_alloc_preg (cfg);
1850 MONO_ADD_INS (cfg->cbb, ins);
1851 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, cinfo->ret.reg, FALSE);
1854 for (i = 0; i < n; ++i) {
1855 MonoType *t;
1857 ainfo = cinfo->args + i;
1858 if (i >= sig->hasthis)
1859 t = sig->params [i - sig->hasthis];
1860 else
1861 t = mono_get_int_type ();
1862 t = mini_get_underlying_type (t);
1864 in = call->args [i];
1866 if ((sig->call_convention == MONO_CALL_VARARG) &&
1867 (!sig->pinvoke) &&
1868 (i == sig->sentinelpos)) {
1869 emit_sig_cookie (cfg, call, cinfo);
1872 switch (ainfo->regtype) {
1873 case RegTypeGeneral :
1874 add_outarg_reg2 (cfg, call, ainfo->regtype, ainfo->reg, in);
1875 break;
1876 case RegTypeFP :
1877 case RegTypeFPR4 :
1878 if (MONO_TYPE_ISSTRUCT (t)) {
1879 /* Valuetype passed in one fp register */
1880 ainfo->regtype = RegTypeStructByValInFP;
1881 /* Fall through */
1882 } else {
1883 add_outarg_reg2 (cfg, call, ainfo->regtype, ainfo->reg, in);
1884 break;
1886 case RegTypeStructByVal :
1887 case RegTypeStructByAddr :
1888 case RegTypeStructByAddrOnStack : {
1889 guint32 align;
1890 guint32 size;
1892 if (sig->params [i - sig->hasthis]->type == MONO_TYPE_TYPEDBYREF) {
1893 size = MONO_ABI_SIZEOF (MonoTypedRef);
1894 align = sizeof (target_mgreg_t);
1896 else
1897 if (sig->pinvoke)
1898 size = mono_type_native_stack_size (m_class_get_byval_arg (in->klass), &align);
1899 else {
1901 * Other backends use mono_type_stack_size (), but that
1902 * aligns the size to 8, which is larger than the size of
1903 * the source, leading to reads of invalid memory if the
1904 * source is at the end of address space.
1906 size = mono_class_value_size (in->klass, &align);
1909 g_assert (in->klass);
1911 ainfo->offparm += cinfo->sz.offStruct;
1913 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1914 ins->sreg1 = in->dreg;
1915 ins->klass = in->klass;
1916 ins->backend.size = ainfo->size;
1917 ins->inst_p0 = call;
1918 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1919 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1921 MONO_ADD_INS (cfg->cbb, ins);
1923 break;
1925 case RegTypeBase :
1926 if (!t->byref && t->type == MONO_TYPE_R4) {
1927 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG,
1928 STK_BASE, ainfo->offset + 4,
1929 in->dreg);
1930 } else if (!t->byref && (t->type == MONO_TYPE_R8)) {
1931 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG,
1932 STK_BASE, ainfo->offset,
1933 in->dreg);
1934 } else {
1935 MONO_INST_NEW (cfg, ins, OP_STORE_MEMBASE_REG);
1936 ins->inst_destbasereg = STK_BASE;
1937 ins->inst_offset = ainfo->offset;
1938 ins->sreg1 = in->dreg;
1939 MONO_ADD_INS (cfg->cbb, ins);
1941 break;
1942 default:
1943 g_assert_not_reached ();
1944 break;
1949 * Handle the case where there are no implicit arguments
1951 if ((sig->call_convention == MONO_CALL_VARARG) &&
1952 (!sig->pinvoke) &&
1953 (i == sig->sentinelpos)) {
1954 emit_sig_cookie (cfg, call, cinfo);
1957 if (cinfo->struct_ret) {
1958 MonoInst *vtarg;
1960 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1961 vtarg->sreg1 = call->vret_var->dreg;
1962 vtarg->dreg = mono_alloc_preg (cfg);
1963 MONO_ADD_INS (cfg->cbb, vtarg);
1965 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1969 /*========================= End of Function ========================*/
1971 /*------------------------------------------------------------------*/
1972 /* */
1973 /* Name - mono_arch_emit_outarg_vt */
1974 /* */
1975 /*------------------------------------------------------------------*/
1977 void
1978 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1980 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1981 ArgInfo *ainfo = (ArgInfo*)ins->inst_p1;
1982 int size = ins->backend.size;
1984 if (ainfo->regtype == RegTypeStructByVal) {
1986 arg->ins.sreg1 = ainfo->reg;
1987 arg->ins.opcode = OP_OUTARG_VT;
1988 arg->size = ainfo->size;
1989 arg->offset = ainfo->offset;
1990 arg->offPrm = ainfo->offparm + cinfo->sz.offStruct;
1992 if (ainfo->reg != STK_BASE) {
1993 MONO_OUTPUT_VTR (cfg, size, ainfo->reg, src->dreg, 0);
1994 } else {
1995 MONO_OUTPUT_VTS (cfg, size, ainfo->reg, ainfo->offset,
1996 src->dreg, 0);
1998 } else if (ainfo->regtype == RegTypeStructByValInFP) {
1999 int dreg = mono_alloc_freg (cfg);
2001 if (ainfo->size == 4) {
2002 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, dreg, src->dreg, 0);
2003 MONO_EMIT_NEW_UNALU (cfg, OP_S390_SETF4RET, dreg, dreg);
2004 } else {
2005 g_assert (ainfo->size == 8);
2007 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, dreg, src->dreg, 0);
2010 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
2011 } else {
2012 ERROR_DECL (error);
2013 MonoMethodHeader *header;
2014 MonoInst *vtcopy = mono_compile_create_var (cfg, m_class_get_byval_arg (src->klass), OP_LOCAL);
2015 MonoInst *load;
2016 int ovf_size = ainfo->vtsize,
2017 srcReg;
2018 guint32 size;
2020 /* FIXME: alignment? */
2021 if (call->signature->pinvoke) {
2022 size = mono_type_native_stack_size (m_class_get_byval_arg (src->klass), NULL);
2023 vtcopy->backend.is_pinvoke = 1;
2024 } else {
2025 size = mini_type_stack_size (m_class_get_byval_arg (src->klass), NULL);
2027 if (size > 0)
2028 g_assert (ovf_size > 0);
2030 header = mono_method_get_header_checked (cfg->method, error);
2031 mono_error_assert_ok (error); /* FIXME don't swallow the error */
2032 if ((cfg->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses)
2033 srcReg = s390_r11;
2034 else
2035 srcReg = STK_BASE;
2037 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
2038 mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, size, TARGET_SIZEOF_VOID_P);
2040 if (ainfo->reg == STK_BASE) {
2041 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, srcReg, ainfo->offset, load->dreg);
2043 if (cfg->compute_gc_maps) {
2044 MonoInst *def;
2046 EMIT_NEW_GC_PARAM_SLOT_LIVENESS_DEF (cfg, def, ainfo->offset, m_class_get_byval_arg (ins->klass));
2048 } else
2049 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
2053 /*========================= End of Function ========================*/
2055 /*------------------------------------------------------------------*/
2056 /* */
2057 /* Name - mono_arch_emit_setret */
2058 /* */
2059 /*------------------------------------------------------------------*/
2061 void
2062 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
2064 MonoType *ret = mini_get_underlying_type (mono_method_signature_internal (method)->ret);
2066 if (!ret->byref) {
2067 if (ret->type == MONO_TYPE_R4) {
2068 MONO_EMIT_NEW_UNALU (cfg, OP_S390_SETF4RET, s390_f0, val->dreg);
2069 return;
2070 } else if (ret->type == MONO_TYPE_R8) {
2071 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, s390_f0, val->dreg);
2072 return;
2076 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
2079 /*========================= End of Function ========================*/
2081 /*------------------------------------------------------------------*/
2082 /* */
2083 /* Name - compare_and_branch */
2084 /* */
2085 /* Function - Form a peephole pass at the code looking for */
2086 /* simple optimizations. */
2087 /* */
2088 /*------------------------------------------------------------------*/
2090 static void
2091 compare_and_branch(MonoBasicBlock *bb, MonoInst *ins, int cc, gboolean logical)
2093 MonoInst *last;
2095 if (mono_hwcap_s390x_has_gie) {
2096 last = mono_inst_prev (ins, FILTER_IL_SEQ_POINT);
2097 ins->sreg1 = last->sreg1;
2098 ins->sreg2 = last->sreg2;
2099 ins->sreg3 = cc;
2100 switch(last->opcode) {
2101 case OP_ICOMPARE:
2102 if (logical)
2103 ins->opcode = OP_S390_CLRJ;
2104 else
2105 ins->opcode = OP_S390_CRJ;
2106 MONO_DELETE_INS(bb, last);
2107 break;
2108 case OP_COMPARE:
2109 case OP_LCOMPARE:
2110 if (logical)
2111 ins->opcode = OP_S390_CLGRJ;
2112 else
2113 ins->opcode = OP_S390_CGRJ;
2114 MONO_DELETE_INS(bb, last);
2115 break;
2116 case OP_ICOMPARE_IMM:
2117 ins->backend.data = (gpointer) last->inst_imm;
2118 if (logical)
2119 ins->opcode = OP_S390_CLIJ;
2120 else
2121 ins->opcode = OP_S390_CIJ;
2122 MONO_DELETE_INS(bb, last);
2123 break;
2124 case OP_COMPARE_IMM:
2125 case OP_LCOMPARE_IMM:
2126 ins->backend.data = (gpointer) last->inst_imm;
2127 if (logical)
2128 ins->opcode = OP_S390_CLGIJ;
2129 else
2130 ins->opcode = OP_S390_CGIJ;
2131 MONO_DELETE_INS(bb, last);
2132 break;
2137 /*========================= End of Function ========================*/
2139 /*------------------------------------------------------------------*/
2140 /* */
2141 /* Name - mono_arch_peephole_pass_1 */
2142 /* */
2143 /* Function - Form a peephole pass at the code looking for */
2144 /* simple optimizations. */
2145 /* */
2146 /*------------------------------------------------------------------*/
2148 void
2149 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
2151 MonoInst *ins, *n;
2153 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
2154 switch (ins->opcode) {
2155 case OP_IBEQ:
2156 case OP_LBEQ:
2157 compare_and_branch(bb, ins, S390_CC_EQ, FALSE);
2158 break;
2159 case OP_LBNE_UN:
2160 case OP_IBNE_UN:
2161 compare_and_branch(bb, ins, S390_CC_NE, TRUE);
2162 break;
2163 case OP_LBLT:
2164 case OP_IBLT:
2165 compare_and_branch(bb, ins, S390_CC_LT, FALSE);
2166 break;
2167 case OP_LBLT_UN:
2168 case OP_IBLT_UN:
2169 compare_and_branch(bb, ins, S390_CC_LT, TRUE);
2170 break;
2171 case OP_LBGT:
2172 case OP_IBGT:
2173 compare_and_branch(bb, ins, S390_CC_GT, FALSE);
2174 break;
2175 case OP_LBGT_UN:
2176 case OP_IBGT_UN:
2177 compare_and_branch(bb, ins, S390_CC_GT, TRUE);
2178 break;
2179 case OP_LBGE:
2180 case OP_IBGE:
2181 compare_and_branch(bb, ins, S390_CC_GE, FALSE);
2182 break;
2183 case OP_LBGE_UN:
2184 case OP_IBGE_UN:
2185 compare_and_branch(bb, ins, S390_CC_GE, TRUE);
2186 break;
2187 case OP_LBLE:
2188 case OP_IBLE:
2189 compare_and_branch(bb, ins, S390_CC_LE, FALSE);
2190 break;
2191 case OP_LBLE_UN:
2192 case OP_IBLE_UN:
2193 compare_and_branch(bb, ins, S390_CC_LE, TRUE);
2194 break;
2196 // default:
2197 // mono_peephole_ins (bb, ins);
2202 /*========================= End of Function ========================*/
2204 /*------------------------------------------------------------------*/
2205 /* */
2206 /* Name - mono_arch_peephole_pass_2 */
2207 /* */
2208 /* Function - Form a peephole pass at the code looking for */
2209 /* simple optimizations. */
2210 /* */
2211 /*------------------------------------------------------------------*/
2213 void
2214 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
2216 MonoInst *ins, *n, *last_ins = NULL;
2218 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
2219 switch (ins->opcode) {
2220 case OP_LOADU4_MEMBASE:
2221 case OP_LOADI4_MEMBASE:
2222 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG) &&
2223 ins->inst_basereg == last_ins->inst_destbasereg &&
2224 ins->inst_offset == last_ins->inst_offset) {
2225 ins->opcode = (ins->opcode == OP_LOADI4_MEMBASE) ? OP_ICONV_TO_I4 : OP_ICONV_TO_U4;
2226 ins->sreg1 = last_ins->sreg1;
2228 break;
2230 mono_peephole_ins (bb, ins);
2234 /*========================= End of Function ========================*/
2236 /*------------------------------------------------------------------*/
2237 /* */
2238 /* Name - mono_arch_lowering_pass. */
2239 /* */
2240 /*------------------------------------------------------------------*/
2242 void
2243 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2245 MonoInst *ins, *next;
2247 MONO_BB_FOR_EACH_INS_SAFE (bb, next, ins) {
2248 switch (ins->opcode) {
2249 case OP_DIV_IMM:
2250 case OP_REM_IMM:
2251 case OP_IDIV_IMM:
2252 case OP_IREM_IMM:
2253 case OP_IDIV_UN_IMM:
2254 case OP_IREM_UN_IMM:
2255 case OP_LAND_IMM:
2256 case OP_LOR_IMM:
2257 case OP_LREM_IMM:
2258 case OP_LXOR_IMM:
2259 case OP_LOCALLOC_IMM:
2260 mono_decompose_op_imm (cfg, bb, ins);
2261 break;
2262 case OP_LADD_IMM:
2263 if (!s390_is_imm16 (ins->inst_imm))
2264 /* This is created by the memcpy code which ignores is_inst_imm */
2265 mono_decompose_op_imm (cfg, bb, ins);
2266 break;
2267 default:
2268 break;
2272 bb->max_vreg = cfg->next_vreg;
2275 /*========================= End of Function ========================*/
2277 /*------------------------------------------------------------------*/
2278 /* */
2279 /* Name - emit_float_to_int */
2280 /* */
2281 /* Function - Create instructions which will convert a floating */
2282 /* point value to integer. */
2283 /* */
2284 /*------------------------------------------------------------------*/
2286 static guchar*
2287 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
2289 /* sreg is a float, dreg is an integer reg. */
2290 if (is_signed) {
2291 s390_cgebr (code, dreg, 5, sreg);
2292 switch (size) {
2293 case 1:
2294 s390_ltgr (code, dreg, dreg);
2295 s390_jnl (code, 4);
2296 s390_oill (code, dreg, 0x80);
2297 s390_lghi (code, s390_r0, 0xff);
2298 s390_ngr (code, dreg, s390_r0);
2299 break;
2300 case 2:
2301 s390_ltgr (code, dreg, dreg);
2302 s390_jnl (code, 4);
2303 s390_oill (code, dreg, 0x8000);
2304 s390_llill(code, s390_r0, 0xffff);
2305 s390_ngr (code, dreg, s390_r0);
2306 break;
2308 } else {
2309 short *o[1];
2310 S390_SET (code, s390_r13, 0x4f000000u);
2311 s390_ldgr (code, s390_f14, s390_r13);
2312 s390_ler (code, s390_f15, sreg);
2313 s390_cebr (code, s390_f15, s390_f14);
2314 s390_jl (code, 0); CODEPTR (code, o[0]);
2315 S390_SET (code, s390_r13, 0x4f800000u);
2316 s390_ldgr (code, s390_f14, s390_r13);
2317 s390_sebr (code, s390_f15, s390_f14);
2318 s390_cfebr (code, dreg, 7, s390_f15);
2319 s390_j (code, 4);
2320 PTRSLOT (code, o[0]);
2321 s390_cfebr (code, dreg, 5, sreg);
2322 switch (size) {
2323 case 1:
2324 s390_lghi (code, s390_r0, 0xff);
2325 s390_ngr (code, dreg, s390_r0);
2326 break;
2327 case 2:
2328 s390_llill(code, s390_r0, 0xffff);
2329 s390_ngr (code, dreg, s390_r0);
2330 break;
2333 return code;
2336 /*========================= End of Function ========================*/
2338 /*------------------------------------------------------------------*/
2339 /* */
2340 /* Name - emit_double_to_int */
2341 /* */
2342 /* Function - Create instructions which will convert a floating */
2343 /* point value to integer. */
2344 /* */
2345 /*------------------------------------------------------------------*/
2347 static guchar*
2348 emit_double_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
2350 /* sreg is a float, dreg is an integer reg. */
2351 if (is_signed) {
2352 s390_cgdbr (code, dreg, 5, sreg);
2353 switch (size) {
2354 case 1:
2355 s390_ltgr (code, dreg, dreg);
2356 s390_jnl (code, 4);
2357 s390_oill (code, dreg, 0x80);
2358 s390_lghi (code, s390_r0, 0xff);
2359 s390_ngr (code, dreg, s390_r0);
2360 break;
2361 case 2:
2362 s390_ltgr (code, dreg, dreg);
2363 s390_jnl (code, 4);
2364 s390_oill (code, dreg, 0x8000);
2365 s390_llill(code, s390_r0, 0xffff);
2366 s390_ngr (code, dreg, s390_r0);
2367 break;
2369 } else {
2370 short *o[1];
2371 S390_SET (code, s390_r13, 0x41e0000000000000llu);
2372 s390_ldgr (code, s390_f14, s390_r13);
2373 s390_ldr (code, s390_f15, sreg);
2374 s390_cdbr (code, s390_f15, s390_f14);
2375 s390_jl (code, 0); CODEPTR (code, o[0]);
2376 S390_SET (code, s390_r13, 0x41f0000000000000llu);
2377 s390_ldgr (code, s390_f14, s390_r13);
2378 s390_sdbr (code, s390_f15, s390_f14);
2379 s390_cfdbr (code, dreg, 7, s390_f15);
2380 s390_j (code, 4);
2381 PTRSLOT (code, o[0]);
2382 s390_cfdbr (code, dreg, 5, sreg);
2383 switch (size) {
2384 case 1:
2385 s390_lghi (code, s390_r0, 0xff);
2386 s390_ngr (code, dreg, s390_r0);
2387 break;
2388 case 2:
2389 s390_llill(code, s390_r0, 0xffff);
2390 s390_ngr (code, dreg, s390_r0);
2391 break;
2394 return code;
2397 /*========================= End of Function ========================*/
2399 /*------------------------------------------------------------------*/
2400 /* */
2401 /* Name - is_unsigned. */
2402 /* */
2403 /* Function - Return TRUE if next opcode is checking for un- */
2404 /* signed value. */
2405 /* */
2406 /*------------------------------------------------------------------*/
2408 static gboolean
2409 is_unsigned (MonoInst *next)
2411 if ((next) &&
2412 (((next->opcode >= OP_IBNE_UN) &&
2413 (next->opcode <= OP_IBLT_UN)) ||
2414 ((next->opcode >= OP_LBNE_UN) &&
2415 (next->opcode <= OP_LBLT_UN)) ||
2416 ((next->opcode >= OP_COND_EXC_NE_UN) &&
2417 (next->opcode <= OP_COND_EXC_LT_UN)) ||
2418 ((next->opcode >= OP_COND_EXC_INE_UN) &&
2419 (next->opcode <= OP_COND_EXC_ILT_UN)) ||
2420 ((next->opcode == OP_CLT_UN) ||
2421 (next->opcode == OP_CGT_UN) ||
2422 (next->opcode == OP_ICGE_UN) ||
2423 (next->opcode == OP_ICLE_UN)) ||
2424 ((next->opcode == OP_ICLT_UN) ||
2425 (next->opcode == OP_ICGT_UN) ||
2426 (next->opcode == OP_LCLT_UN) ||
2427 (next->opcode == OP_LCGT_UN))))
2428 return TRUE;
2429 else
2430 return FALSE;
2433 /*========================= End of Function ========================*/
2435 /*------------------------------------------------------------------*/
2436 /* */
2437 /* Name - mono_arch_output_basic_block */
2438 /* */
2439 /* Function - Perform the "real" work of emitting instructions */
2440 /* that will do the work of in the basic block. */
2441 /* */
2442 /*------------------------------------------------------------------*/
2444 void
2445 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2447 MonoInst *ins;
2448 MonoCallInst *call;
2449 guint8 *code = cfg->native_code + cfg->code_len;
2450 int src2;
2452 /* we don't align basic blocks of loops on s390 */
2454 if (cfg->verbose_level > 2)
2455 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
2457 MONO_BB_FOR_EACH_INS (bb, ins) {
2458 const guint offset = code - cfg->native_code;
2459 set_code_cursor (cfg, code);
2460 int max_len = ins_get_size (ins->opcode);
2461 code = realloc_code (cfg, max_len);
2463 mono_debug_record_line_number (cfg, ins, offset);
2465 switch (ins->opcode) {
2466 case OP_STOREI1_MEMBASE_IMM: {
2467 s390_lghi (code, s390_r0, ins->inst_imm);
2468 S390_LONG (code, stcy, stc, s390_r0, 0,
2469 ins->inst_destbasereg, ins->inst_offset);
2471 break;
2472 case OP_STOREI2_MEMBASE_IMM: {
2473 s390_lghi (code, s390_r0, ins->inst_imm);
2474 S390_LONG (code, sthy, sth, s390_r0, 0,
2475 ins->inst_destbasereg, ins->inst_offset);
2477 break;
2478 case OP_STOREI4_MEMBASE_IMM: {
2479 s390_lgfi (code, s390_r0, ins->inst_imm);
2480 S390_LONG (code, sty, st, s390_r0, 0,
2481 ins->inst_destbasereg, ins->inst_offset);
2483 break;
2484 case OP_STORE_MEMBASE_IMM:
2485 case OP_STOREI8_MEMBASE_IMM: {
2486 S390_SET (code, s390_r0, ins->inst_imm);
2487 S390_LONG (code, stg, stg, s390_r0, 0,
2488 ins->inst_destbasereg, ins->inst_offset);
2490 break;
2491 case OP_STOREI1_MEMBASE_REG: {
2492 S390_LONG (code, stcy, stc, ins->sreg1, 0,
2493 ins->inst_destbasereg, ins->inst_offset);
2495 break;
2496 case OP_STOREI2_MEMBASE_REG: {
2497 S390_LONG (code, sthy, sth, ins->sreg1, 0,
2498 ins->inst_destbasereg, ins->inst_offset);
2500 break;
2501 case OP_STOREI4_MEMBASE_REG: {
2502 S390_LONG (code, sty, st, ins->sreg1, 0,
2503 ins->inst_destbasereg, ins->inst_offset);
2505 break;
2506 case OP_STORE_MEMBASE_REG:
2507 case OP_STOREI8_MEMBASE_REG: {
2508 S390_LONG (code, stg, stg, ins->sreg1, 0,
2509 ins->inst_destbasereg, ins->inst_offset);
2511 break;
2512 case OP_LOADU4_MEM:
2513 g_assert_not_reached ();
2514 break;
2515 case OP_LOAD_MEMBASE:
2516 case OP_LOADI8_MEMBASE: {
2517 S390_LONG (code, lg, lg, ins->dreg, 0,
2518 ins->inst_basereg, ins->inst_offset);
2520 break;
2521 case OP_LOADI4_MEMBASE: {
2522 S390_LONG (code, lgf, lgf, ins->dreg, 0,
2523 ins->inst_basereg, ins->inst_offset);
2525 break;
2526 case OP_LOADU4_MEMBASE: {
2527 S390_LONG (code, llgf, llgf, ins->dreg, 0,
2528 ins->inst_basereg, ins->inst_offset);
2530 break;
2531 case OP_LOADU1_MEMBASE: {
2532 S390_LONG (code, llgc, llgc, ins->dreg, 0,
2533 ins->inst_basereg, ins->inst_offset);
2535 break;
2536 case OP_LOADI1_MEMBASE: {
2537 S390_LONG (code, lgb, lgb, ins->dreg, 0,
2538 ins->inst_basereg, ins->inst_offset);
2540 break;
2541 case OP_LOADU2_MEMBASE: {
2542 S390_LONG (code, llgh, llgh, ins->dreg, 0,
2543 ins->inst_basereg, ins->inst_offset);
2545 break;
2546 case OP_LOADI2_MEMBASE: {
2547 S390_LONG (code, lgh, lgh, ins->dreg, 0,
2548 ins->inst_basereg, ins->inst_offset);
2550 break;
2551 case OP_LCONV_TO_I1: {
2552 s390_lgbr (code, ins->dreg, ins->sreg1);
2554 break;
2555 case OP_LCONV_TO_I2: {
2556 s390_lghr (code, ins->dreg, ins->sreg1);
2558 break;
2559 case OP_LCONV_TO_U1: {
2560 s390_llgcr (code, ins->dreg, ins->sreg1);
2562 break;
2563 case OP_LCONV_TO_U2: {
2564 s390_llghr (code, ins->dreg, ins->sreg1);
2566 break;
2567 case OP_ICONV_TO_I1: {
2568 s390_lgbr (code, ins->dreg, ins->sreg1);
2570 break;
2571 case OP_ICONV_TO_I2: {
2572 s390_lghr (code, ins->dreg, ins->sreg1);
2574 break;
2575 case OP_ICONV_TO_U1: {
2576 s390_llgcr (code, ins->dreg, ins->sreg1);
2578 break;
2579 case OP_ICONV_TO_U2: {
2580 s390_llghr (code, ins->dreg, ins->sreg1);
2582 break;
2583 case OP_ICONV_TO_U4: {
2584 s390_llgfr (code, ins->dreg, ins->sreg1);
2586 break;
2587 case OP_ICONV_TO_I4: {
2588 s390_lgfr (code, ins->dreg, ins->sreg1);
2590 break;
2591 case OP_COMPARE:
2592 case OP_LCOMPARE: {
2593 if (is_unsigned (ins->next))
2594 s390_clgr (code, ins->sreg1, ins->sreg2);
2595 else
2596 s390_cgr (code, ins->sreg1, ins->sreg2);
2598 break;
2599 case OP_ICOMPARE: {
2600 if (is_unsigned (ins->next))
2601 s390_clr (code, ins->sreg1, ins->sreg2);
2602 else
2603 s390_cr (code, ins->sreg1, ins->sreg2);
2605 break;
2606 case OP_COMPARE_IMM:
2607 case OP_LCOMPARE_IMM: {
2608 gboolean branchUn = is_unsigned (ins->next);
2609 if ((ins->inst_imm == 0) && (!branchUn)) {
2610 s390_ltgr (code, ins->sreg1, ins->sreg1);
2611 } else {
2612 S390_SET (code, s390_r0, ins->inst_imm);
2613 if (branchUn)
2614 s390_clgr (code, ins->sreg1, s390_r0);
2615 else
2616 s390_cgr (code, ins->sreg1, s390_r0);
2619 break;
2620 case OP_ICOMPARE_IMM: {
2621 gboolean branchUn = is_unsigned (ins->next);
2622 if ((ins->inst_imm == 0) && (!branchUn)) {
2623 s390_ltr (code, ins->sreg1, ins->sreg1);
2624 } else {
2625 S390_SET (code, s390_r0, ins->inst_imm);
2626 if (branchUn)
2627 s390_clr (code, ins->sreg1, s390_r0);
2628 else
2629 s390_cr (code, ins->sreg1, s390_r0);
2632 break;
2633 case OP_BREAK: {
2634 mono_add_patch_info (cfg, code - cfg->native_code,
2635 MONO_PATCH_INFO_JIT_ICALL_ID,
2636 GUINT_TO_POINTER (MONO_JIT_ICALL_mono_break));
2637 S390_CALL_TEMPLATE (code, s390_r14);
2639 break;
2640 case OP_ADDCC: {
2641 if (mono_hwcap_s390x_has_mlt) {
2642 s390_agrk (code, ins->dreg, ins->sreg1, ins->sreg2);
2643 } else {
2644 CHECK_SRCDST_COM;
2645 s390_agr (code, ins->dreg, src2);
2648 break;
2649 case OP_LADD: {
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_ADC: {
2659 CHECK_SRCDST_COM;
2660 s390_alcgr (code, ins->dreg, src2);
2662 break;
2663 case OP_ADD_IMM: {
2664 if (mono_hwcap_s390x_has_mlt) {
2665 if (s390_is_imm16 (ins->inst_imm)) {
2666 s390_aghik(code, ins->dreg, ins->sreg1, ins->inst_imm);
2667 } else {
2668 S390_SET (code, s390_r0, ins->inst_imm);
2669 s390_agrk (code, ins->dreg, ins->sreg1, s390_r0);
2671 } else {
2672 if (ins->dreg != ins->sreg1) {
2673 s390_lgr (code, ins->dreg, ins->sreg1);
2675 if (s390_is_imm16 (ins->inst_imm)) {
2676 s390_aghi (code, ins->dreg, ins->inst_imm);
2677 } else if (s390_is_imm32 (ins->inst_imm)) {
2678 s390_agfi (code, ins->dreg, ins->inst_imm);
2679 } else {
2680 S390_SET (code, s390_r0, ins->inst_imm);
2681 s390_agr (code, ins->dreg, s390_r0);
2685 break;
2686 case OP_LADD_IMM: {
2687 if (ins->dreg != ins->sreg1) {
2688 s390_lgr (code, ins->dreg, ins->sreg1);
2690 if (s390_is_imm32 (ins->inst_imm)) {
2691 s390_agfi (code, ins->dreg, ins->inst_imm);
2692 } else {
2693 S390_SET (code, s390_r0, ins->inst_imm);
2694 s390_agr (code, ins->dreg, s390_r0);
2697 break;
2698 case OP_ADC_IMM: {
2699 if (ins->dreg != ins->sreg1) {
2700 s390_lgr (code, ins->dreg, ins->sreg1);
2702 if (s390_is_imm16 (ins->inst_imm)) {
2703 s390_lghi (code, s390_r0, ins->inst_imm);
2704 s390_alcgr (code, ins->dreg, s390_r0);
2705 } else {
2706 S390_SET (code, s390_r0, ins->inst_imm);
2707 s390_alcgr (code, ins->dreg, s390_r0);
2710 break;
2711 case OP_IADD_OVF:
2712 case OP_S390_IADD_OVF: {
2713 CHECK_SRCDST_COM;
2714 s390_ar (code, ins->dreg, src2);
2715 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_OV, "OverflowException");
2716 s390_lgfr (code, ins->dreg, ins->dreg);
2718 break;
2719 case OP_IADD_OVF_UN:
2720 case OP_S390_IADD_OVF_UN: {
2721 CHECK_SRCDST_COM;
2722 s390_algr (code, ins->dreg, src2);
2723 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_CY, "OverflowException");
2724 s390_llgfr (code, ins->dreg, ins->dreg);
2726 break;
2727 case OP_ADD_OVF_CARRY: {
2728 CHECK_SRCDST_COM;
2729 s390_lghi (code, s390_r0, 0);
2730 s390_lgr (code, s390_r1, s390_r0);
2731 s390_alcgr (code, s390_r0, s390_r1);
2732 s390_agr (code, ins->dreg, src2);
2733 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_OV, "OverflowException");
2734 s390_agr (code, ins->dreg, s390_r0);
2735 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_OV, "OverflowException");
2737 break;
2738 case OP_ADD_OVF_UN_CARRY: {
2739 CHECK_SRCDST_COM;
2740 s390_alcgr (code, ins->dreg, src2);
2741 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_CY, "OverflowException");
2743 break;
2744 case OP_SUBCC: {
2745 if (mono_hwcap_s390x_has_mlt) {
2746 s390_sgrk (code, ins->dreg, ins->sreg1, ins->sreg2);
2747 } else {
2748 CHECK_SRCDST_NCOM;
2749 s390_sgr (code, ins->dreg, src2);
2752 break;
2753 case OP_LSUB: {
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_SBB: {
2763 CHECK_SRCDST_NCOM;
2764 s390_slbgr(code, ins->dreg, src2);
2766 break;
2767 case OP_SUB_IMM: {
2768 if (ins->dreg != ins->sreg1) {
2769 s390_lgr (code, ins->dreg, ins->sreg1);
2771 if (s390_is_imm16 (-ins->inst_imm)) {
2772 s390_aghi (code, ins->dreg, -ins->inst_imm);
2773 } else if (s390_is_imm32 (-ins->inst_imm)) {
2774 s390_slgfi (code, ins->dreg, ins->inst_imm);
2775 } else {
2776 S390_SET (code, s390_r0, ins->inst_imm);
2777 s390_slgr (code, ins->dreg, s390_r0);
2780 break;
2781 case OP_LSUB_IMM: {
2782 if (ins->dreg != ins->sreg1) {
2783 s390_lgr (code, ins->dreg, ins->sreg1);
2785 if (s390_is_imm16 (-ins->inst_imm)) {
2786 s390_aghi (code, ins->dreg, -ins->inst_imm);
2787 } else if (s390_is_imm32 (-ins->inst_imm)) {
2788 s390_slgfi (code, ins->dreg, ins->inst_imm);
2789 } else {
2790 S390_SET (code, s390_r0, ins->inst_imm);
2791 s390_slgr (code, ins->dreg, s390_r0);
2794 break;
2795 case OP_SBB_IMM: {
2796 if (ins->dreg != ins->sreg1) {
2797 s390_lgr (code, ins->dreg, ins->sreg1);
2799 if (s390_is_imm16 (-ins->inst_imm)) {
2800 s390_lghi (code, s390_r0, ins->inst_imm);
2801 s390_slbgr (code, ins->dreg, s390_r0);
2802 } else {
2803 S390_SET (code, s390_r0, ins->inst_imm);
2804 s390_slbgr(code, ins->dreg, s390_r0);
2807 break;
2808 case OP_SUB_OVF_CARRY: {
2809 CHECK_SRCDST_NCOM;
2810 s390_lghi (code, s390_r0, 0);
2811 s390_lgr (code, s390_r1, s390_r0);
2812 s390_slbgr (code, s390_r0, s390_r1);
2813 s390_sgr (code, ins->dreg, src2);
2814 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_OV, "OverflowException");
2815 s390_agr (code, ins->dreg, s390_r0);
2816 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_OV, "OverflowException");
2818 break;
2819 case OP_SUB_OVF_UN_CARRY: {
2820 CHECK_SRCDST_NCOM;
2821 s390_slbgr (code, ins->dreg, src2);
2822 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_NC, "OverflowException");
2824 break;
2825 case OP_LAND: {
2826 if (mono_hwcap_s390x_has_mlt) {
2827 s390_ngrk (code, ins->dreg, ins->sreg1, ins->sreg2);
2828 } else {
2829 if (ins->sreg1 == ins->dreg) {
2830 s390_ngr (code, ins->dreg, ins->sreg2);
2831 } else {
2832 if (ins->sreg2 == ins->dreg) {
2833 s390_ngr (code, ins->dreg, ins->sreg1);
2834 } else {
2835 s390_lgr (code, ins->dreg, ins->sreg1);
2836 s390_ngr (code, ins->dreg, ins->sreg2);
2841 break;
2842 case OP_AND_IMM: {
2843 S390_SET_MASK (code, s390_r0, ins->inst_imm);
2844 if (mono_hwcap_s390x_has_mlt) {
2845 s390_ngrk (code, ins->dreg, ins->sreg1, s390_r0);
2846 } else {
2847 if (ins->dreg != ins->sreg1) {
2848 s390_lgr (code, ins->dreg, ins->sreg1);
2850 s390_ngr (code, ins->dreg, s390_r0);
2853 break;
2854 case OP_LDIV: {
2855 s390_lgr (code, s390_r1, ins->sreg1);
2856 s390_dsgr (code, s390_r0, ins->sreg2);
2857 s390_lgr (code, ins->dreg, s390_r1);
2859 break;
2860 case OP_LDIV_UN: {
2861 s390_lgr (code, s390_r1, ins->sreg1);
2862 s390_lghi (code, s390_r0, 0);
2863 s390_dlgr (code, s390_r0, ins->sreg2);
2864 s390_lgr (code, ins->dreg, s390_r1);
2866 break;
2867 case OP_LREM: {
2868 s390_lgr (code, s390_r1, ins->sreg1);
2869 s390_dsgr (code, s390_r0, ins->sreg2);
2870 s390_lgr (code, ins->dreg, s390_r0);
2871 break;
2873 case OP_LREM_IMM: {
2874 if (s390_is_imm16 (ins->inst_imm)) {
2875 s390_lghi (code, s390_r13, ins->inst_imm);
2876 } else {
2877 s390_lgfi (code, s390_r13, ins->inst_imm);
2879 s390_lgr (code, s390_r0, ins->sreg1);
2880 s390_dsgr (code, s390_r0, s390_r13);
2881 s390_lgfr (code, ins->dreg, s390_r0);
2883 break;
2884 case OP_LREM_UN: {
2885 s390_lgr (code, s390_r1, ins->sreg1);
2886 s390_lghi (code, s390_r0, 0);
2887 s390_dlgr (code, s390_r0, ins->sreg2);
2888 s390_lgr (code, ins->dreg, s390_r0);
2890 break;
2891 case OP_LOR: {
2892 if (mono_hwcap_s390x_has_mlt) {
2893 s390_ogrk (code, ins->dreg, ins->sreg1, ins->sreg2);
2894 } else {
2895 if (ins->sreg1 == ins->dreg) {
2896 s390_ogr (code, ins->dreg, ins->sreg2);
2897 } else {
2898 if (ins->sreg2 == ins->dreg) {
2899 s390_ogr (code, ins->dreg, ins->sreg1);
2900 } else {
2901 s390_lgr (code, ins->dreg, ins->sreg1);
2902 s390_ogr (code, ins->dreg, ins->sreg2);
2907 break;
2908 case OP_OR_IMM: {
2909 S390_SET_MASK(code, s390_r0, ins->inst_imm);
2910 if (mono_hwcap_s390x_has_mlt) {
2911 s390_ogrk (code, ins->dreg, ins->sreg1, s390_r0);
2912 } else {
2913 if (ins->dreg != ins->sreg1) {
2914 s390_lgr (code, ins->dreg, ins->sreg1);
2916 s390_ogr (code, ins->dreg, s390_r0);
2919 break;
2920 case OP_LXOR: {
2921 if (mono_hwcap_s390x_has_mlt) {
2922 s390_xgrk (code, ins->dreg, ins->sreg1, ins->sreg2);
2923 } else {
2924 if (ins->sreg1 == ins->dreg) {
2925 s390_xgr (code, ins->dreg, ins->sreg2);
2927 else {
2928 if (ins->sreg2 == ins->dreg) {
2929 s390_xgr (code, ins->dreg, ins->sreg1);
2931 else {
2932 s390_lgr (code, ins->dreg, ins->sreg1);
2933 s390_xgr (code, ins->dreg, ins->sreg2);
2938 break;
2939 case OP_XOR_IMM: {
2940 S390_SET_MASK(code, s390_r0, ins->inst_imm);
2941 if (mono_hwcap_s390x_has_mlt) {
2942 s390_xgrk (code, ins->dreg, ins->sreg1, s390_r0);
2943 } else {
2944 if (ins->dreg != ins->sreg1) {
2945 s390_lgr (code, ins->dreg, ins->sreg1);
2947 s390_xgr (code, ins->dreg, s390_r0);
2950 break;
2951 case OP_LSHL: {
2952 CHECK_SRCDST_NCOM;
2953 s390_sllg (code, ins->dreg, ins->dreg, src2, 0);
2955 break;
2956 case OP_SHL_IMM:
2957 case OP_LSHL_IMM: {
2958 if (ins->sreg1 != ins->dreg) {
2959 s390_lgr (code, ins->dreg, ins->sreg1);
2961 s390_sllg (code, ins->dreg, ins->dreg, 0, (ins->inst_imm & 0x3f));
2963 break;
2964 case OP_LSHR: {
2965 CHECK_SRCDST_NCOM;
2966 s390_srag (code, ins->dreg, ins->dreg, src2, 0);
2968 break;
2969 case OP_SHR_IMM:
2970 case OP_LSHR_IMM: {
2971 if (ins->sreg1 != ins->dreg) {
2972 s390_lgr (code, ins->dreg, ins->sreg1);
2974 s390_srag (code, ins->dreg, ins->dreg, 0, (ins->inst_imm & 0x3f));
2976 break;
2977 case OP_SHR_UN_IMM:
2978 case OP_LSHR_UN_IMM: {
2979 if (ins->sreg1 != ins->dreg) {
2980 s390_lgr (code, ins->dreg, ins->sreg1);
2982 s390_srlg (code, ins->dreg, ins->dreg, 0, (ins->inst_imm & 0x3f));
2984 break;
2985 case OP_LSHR_UN: {
2986 CHECK_SRCDST_NCOM;
2987 s390_srlg (code, ins->dreg, ins->dreg, src2, 0);
2989 break;
2990 case OP_LNOT: {
2991 if (ins->sreg1 != ins->dreg) {
2992 s390_lgr (code, ins->dreg, ins->sreg1);
2994 s390_lghi (code, s390_r0, -1);
2995 s390_xgr (code, ins->dreg, s390_r0);
2997 break;
2998 case OP_LNEG: {
2999 s390_lcgr (code, ins->dreg, ins->sreg1);
3001 break;
3002 case OP_LMUL: {
3003 CHECK_SRCDST_COM;
3004 s390_msgr (code, ins->dreg, src2);
3006 break;
3007 case OP_MUL_IMM:
3008 case OP_LMUL_IMM: {
3009 if (ins->dreg != ins->sreg1) {
3010 s390_lgr (code, ins->dreg, ins->sreg1);
3012 if ((mono_hwcap_s390x_has_gie) &&
3013 (s390_is_imm32 (ins->inst_imm))) {
3014 s390_msgfi (code, ins->dreg, ins->inst_imm);
3015 } else {
3016 if (s390_is_imm16 (ins->inst_imm)) {
3017 s390_lghi (code, s390_r13, ins->inst_imm);
3018 } else if (s390_is_imm32 (ins->inst_imm)) {
3019 s390_lgfi (code, s390_r13, ins->inst_imm);
3020 } else {
3021 S390_SET (code, s390_r13, ins->inst_imm);
3023 s390_msgr (code, ins->dreg, s390_r13);
3026 break;
3027 case OP_LMUL_OVF: {
3028 short int *o[2];
3029 if (mono_hwcap_s390x_has_mie2) {
3030 s390_msgrkc (code, ins->dreg, ins->sreg1, ins->sreg2);
3031 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_OV, "OverflowException");
3032 } else {
3033 s390_ltgr (code, s390_r1, ins->sreg1);
3034 s390_jz (code, 0); CODEPTR(code, o[0]);
3035 s390_ltgr (code, s390_r0, ins->sreg2);
3036 s390_jnz (code, 6);
3037 s390_lghi (code, s390_r1, 0);
3038 s390_j (code, 0); CODEPTR(code, o[1]);
3039 s390_xgr (code, s390_r0, s390_r1);
3040 s390_msgr (code, s390_r1, ins->sreg2);
3041 s390_xgr (code, s390_r0, s390_r1);
3042 s390_srlg (code, s390_r0, s390_r0, 0, 63);
3043 s390_ltgr (code, s390_r0, s390_r0);
3044 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_NZ, "OverflowException");
3045 PTRSLOT (code, o[0]);
3046 PTRSLOT (code, o[1]);
3047 s390_lgr (code, ins->dreg, s390_r1);
3050 break;
3051 case OP_LMUL_OVF_UN: {
3052 s390_lghi (code, s390_r0, 0);
3053 s390_lgr (code, s390_r1, ins->sreg1);
3054 s390_mlgr (code, s390_r0, ins->sreg2);
3055 s390_ltgr (code, s390_r0, s390_r0);
3056 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_NZ, "OverflowException");
3057 s390_lgr (code, ins->dreg, s390_r1);
3059 break;
3060 case OP_IADDCC: {
3061 g_assert_not_reached ();
3062 CHECK_SRCDST_COM_I;
3063 s390_algr (code, ins->dreg, src2);
3065 break;
3066 case OP_IADD: {
3067 CHECK_SRCDST_COM_I;
3068 s390_agr (code, ins->dreg, src2);
3070 break;
3071 case OP_IADC: {
3072 g_assert_not_reached ();
3073 CHECK_SRCDST_COM_I;
3074 s390_alcgr (code, ins->dreg, src2);
3076 break;
3077 case OP_IADD_IMM: {
3078 if (ins->dreg != ins->sreg1) {
3079 s390_lgfr (code, ins->dreg, ins->sreg1);
3081 if (s390_is_imm16 (ins->inst_imm)) {
3082 s390_aghi (code, ins->dreg, ins->inst_imm);
3083 } else {
3084 s390_afi (code, ins->dreg, ins->inst_imm);
3087 break;
3088 case OP_IADC_IMM: {
3089 if (ins->dreg != ins->sreg1) {
3090 s390_lgfr (code, ins->dreg, ins->sreg1);
3092 if (s390_is_imm16 (ins->inst_imm)) {
3093 s390_lghi (code, s390_r0, ins->inst_imm);
3094 s390_alcgr (code, ins->dreg, s390_r0);
3095 } else {
3096 S390_SET (code, s390_r0, ins->inst_imm);
3097 s390_alcgr (code, ins->dreg, s390_r0);
3100 break;
3101 case OP_LADD_OVF:
3102 case OP_S390_LADD_OVF: {
3103 if (mono_hwcap_s390x_has_mlt) {
3104 s390_agrk (code, ins->dreg, ins->sreg1, ins->sreg2);
3105 } else {
3106 CHECK_SRCDST_COM;
3107 s390_agr (code, ins->dreg, src2);
3109 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_OV, "OverflowException");
3111 break;
3112 case OP_LADD_OVF_UN:
3113 case OP_S390_LADD_OVF_UN: {
3114 if (mono_hwcap_s390x_has_mlt) {
3115 s390_algrk (code, ins->dreg, ins->sreg1, ins->sreg2);
3116 } else {
3117 CHECK_SRCDST_COM;
3118 s390_algr (code, ins->dreg, src2);
3120 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_CY, "OverflowException");
3122 break;
3123 case OP_ISUBCC: {
3124 if (mono_hwcap_s390x_has_mlt) {
3125 s390_slgrk (code, ins->dreg, ins->sreg1, ins->sreg2);
3126 } else {
3127 CHECK_SRCDST_NCOM_I;
3128 s390_slgr (code, ins->dreg, src2);
3131 break;
3132 case OP_ISUB: {
3133 if (mono_hwcap_s390x_has_mlt) {
3134 s390_sgrk (code, ins->dreg, ins->sreg1, ins->sreg2);
3135 } else {
3136 CHECK_SRCDST_NCOM_I;
3137 s390_sgr (code, ins->dreg, src2);
3140 break;
3141 case OP_ISBB: {
3142 CHECK_SRCDST_NCOM_I;
3143 s390_slbgr (code, ins->dreg, src2);
3145 break;
3146 case OP_ISUB_IMM: {
3147 if (ins->dreg != ins->sreg1) {
3148 s390_lgfr (code, ins->dreg, ins->sreg1);
3150 if (s390_is_imm16 (-ins->inst_imm)) {
3151 s390_aghi (code, ins->dreg, -ins->inst_imm);
3152 } else {
3153 s390_agfi (code, ins->dreg, -ins->inst_imm);
3156 break;
3157 case OP_ISBB_IMM: {
3158 S390_SET (code, s390_r0, ins->inst_imm);
3159 s390_slgfr (code, ins->dreg, s390_r0);
3161 break;
3162 case OP_ISUB_OVF:
3163 case OP_S390_ISUB_OVF: {
3164 if (mono_hwcap_s390x_has_mlt) {
3165 s390_srk (code, ins->dreg, ins->sreg1, ins->sreg2);
3166 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_OV, "OverflowException");
3167 } else {
3168 CHECK_SRCDST_NCOM;
3169 s390_sr (code, ins->dreg, src2);
3170 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_OV, "OverflowException");
3171 s390_lgfr (code, ins->dreg, ins->dreg);
3174 break;
3175 case OP_ISUB_OVF_UN:
3176 case OP_S390_ISUB_OVF_UN: {
3177 if (mono_hwcap_s390x_has_mlt) {
3178 s390_slrk (code, ins->dreg, ins->sreg1, ins->sreg2);
3179 } else {
3180 CHECK_SRCDST_NCOM;
3181 s390_slr (code, ins->dreg, src2);
3183 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_NC, "OverflowException");
3184 s390_llgfr(code, ins->dreg, ins->dreg);
3186 break;
3187 case OP_LSUB_OVF:
3188 case OP_S390_LSUB_OVF: {
3189 if (mono_hwcap_s390x_has_mlt) {
3190 s390_sgrk (code, ins->dreg, ins->sreg1, ins->sreg2);
3191 } else {
3192 CHECK_SRCDST_NCOM;
3193 s390_sgr (code, ins->dreg, src2);
3195 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_OV, "OverflowException");
3197 break;
3198 case OP_LSUB_OVF_UN:
3199 case OP_S390_LSUB_OVF_UN: {
3200 CHECK_SRCDST_NCOM;
3201 s390_slgr (code, ins->dreg, src2);
3202 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_NC, "OverflowException");
3204 break;
3205 case OP_IAND: {
3206 if (mono_hwcap_s390x_has_mlt) {
3207 s390_ngrk (code, ins->dreg, ins->sreg1, ins->sreg2);
3208 } else {
3209 CHECK_SRCDST_NCOM_I;
3210 s390_ngr (code, ins->dreg, src2);
3213 break;
3214 case OP_IAND_IMM: {
3215 S390_SET_MASK (code, s390_r0, ins->inst_imm);
3216 if (mono_hwcap_s390x_has_mlt) {
3217 s390_ngrk (code, ins->dreg, ins->sreg1, s390_r0);
3218 } else {
3219 if (ins->dreg != ins->sreg1) {
3220 s390_lgfr (code, ins->dreg, ins->sreg1);
3222 s390_ngr (code, ins->dreg, s390_r0);
3225 break;
3226 case OP_IDIV: {
3227 s390_lgfr (code, s390_r0, ins->sreg1);
3228 s390_srda (code, s390_r0, 0, 32);
3229 s390_dr (code, s390_r0, ins->sreg2);
3230 s390_lgfr (code, ins->dreg, s390_r1);
3232 break;
3233 case OP_IDIV_UN: {
3234 s390_lgfr (code, s390_r0, ins->sreg1);
3235 s390_srdl (code, s390_r0, 0, 32);
3236 s390_dlr (code, s390_r0, ins->sreg2);
3237 s390_lgfr (code, ins->dreg, s390_r1);
3239 break;
3240 case OP_IDIV_IMM: {
3241 if (s390_is_imm16 (ins->inst_imm)) {
3242 s390_lghi (code, s390_r13, ins->inst_imm);
3243 } else {
3244 s390_lgfi (code, s390_r13, ins->inst_imm);
3246 s390_lgfr (code, s390_r0, ins->sreg1);
3247 s390_srda (code, s390_r0, 0, 32);
3248 s390_dr (code, s390_r0, ins->sreg2);
3249 s390_lgfr (code, ins->dreg, s390_r1);
3251 break;
3252 case OP_IREM: {
3253 s390_lgfr (code, s390_r0, ins->sreg1);
3254 s390_srda (code, s390_r0, 0, 32);
3255 s390_dr (code, s390_r0, ins->sreg2);
3256 s390_lgfr (code, ins->dreg, s390_r0);
3257 break;
3258 case OP_IREM_UN:
3259 s390_lgfr (code, s390_r0, ins->sreg1);
3260 s390_srdl (code, s390_r0, 0, 32);
3261 s390_dlr (code, s390_r0, ins->sreg2);
3262 s390_lgfr (code, ins->dreg, s390_r0);
3264 break;
3265 case OP_IREM_IMM: {
3266 if (s390_is_imm16 (ins->inst_imm)) {
3267 s390_lghi (code, s390_r13, ins->inst_imm);
3268 } else {
3269 s390_lgfi (code, s390_r13, ins->inst_imm);
3271 s390_lgfr (code, s390_r0, ins->sreg1);
3272 s390_srda (code, s390_r0, 0, 32);
3273 s390_dr (code, s390_r0, ins->sreg2);
3274 s390_lgfr (code, ins->dreg, s390_r0);
3276 break;
3277 case OP_IOR: {
3278 if (mono_hwcap_s390x_has_mlt) {
3279 s390_ogrk (code, ins->dreg, ins->sreg1, ins->sreg2);
3280 } else {
3281 CHECK_SRCDST_COM_I;
3282 s390_ogr (code, ins->dreg, src2);
3285 break;
3286 case OP_IOR_IMM: {
3287 S390_SET_MASK (code, s390_r0, ins->inst_imm);
3288 if (mono_hwcap_s390x_has_mlt) {
3289 s390_ogrk (code, ins->dreg, ins->sreg1, s390_r0);
3290 } else {
3291 if (ins->dreg != ins->sreg1) {
3292 s390_lgfr (code, ins->dreg, ins->sreg1);
3294 s390_ogr (code, ins->dreg, s390_r0);
3297 break;
3298 case OP_IXOR: {
3299 if (mono_hwcap_s390x_has_mlt) {
3300 s390_xgrk (code, ins->dreg, ins->sreg1, ins->sreg2);
3301 } else {
3302 CHECK_SRCDST_COM_I;
3303 s390_xgr (code, ins->dreg, src2);
3306 break;
3307 case OP_IXOR_IMM: {
3308 S390_SET_MASK (code, s390_r0, ins->inst_imm);
3309 if (mono_hwcap_s390x_has_mlt) {
3310 s390_xgrk (code, ins->dreg, ins->sreg1, s390_r0);
3311 } else {
3312 if (ins->dreg != ins->sreg1) {
3313 s390_lgfr (code, ins->dreg, ins->sreg1);
3315 s390_xgr (code, ins->dreg, s390_r0);
3318 break;
3319 case OP_ISHL: {
3320 CHECK_SRCDST_NCOM;
3321 s390_sll (code, ins->dreg, src2, 0);
3323 break;
3324 case OP_ISHL_IMM: {
3325 if (ins->sreg1 != ins->dreg) {
3326 s390_lgfr (code, ins->dreg, ins->sreg1);
3328 s390_sll (code, ins->dreg, 0, (ins->inst_imm & 0x1f));
3330 break;
3331 case OP_ISHR: {
3332 CHECK_SRCDST_NCOM;
3333 s390_sra (code, ins->dreg, src2, 0);
3335 break;
3336 case OP_ISHR_IMM: {
3337 if (ins->sreg1 != ins->dreg) {
3338 s390_lgfr (code, ins->dreg, ins->sreg1);
3340 s390_sra (code, ins->dreg, 0, (ins->inst_imm & 0x1f));
3342 break;
3343 case OP_ISHR_UN_IMM: {
3344 if (ins->sreg1 != ins->dreg) {
3345 s390_lgfr (code, ins->dreg, ins->sreg1);
3347 s390_srl (code, ins->dreg, 0, (ins->inst_imm & 0x1f));
3349 break;
3350 case OP_ISHR_UN: {
3351 CHECK_SRCDST_NCOM;
3352 s390_srl (code, ins->dreg, src2, 0);
3354 break;
3355 case OP_INOT: {
3356 if (ins->sreg1 != ins->dreg) {
3357 s390_lgfr (code, ins->dreg, ins->sreg1);
3359 s390_lghi (code, s390_r0, -1);
3360 s390_xgr (code, ins->dreg, s390_r0);
3362 break;
3363 case OP_INEG: {
3364 s390_lcgr (code, ins->dreg, ins->sreg1);
3366 break;
3367 case OP_IMUL: {
3368 CHECK_SRCDST_COM_I;
3369 s390_msr (code, ins->dreg, src2);
3371 break;
3372 case OP_IMUL_IMM: {
3373 if (ins->dreg != ins->sreg1) {
3374 s390_lgfr (code, ins->dreg, ins->sreg1);
3376 if (s390_is_imm16 (ins->inst_imm)) {
3377 s390_lghi (code, s390_r0, ins->inst_imm);
3378 } else {
3379 s390_lgfi (code, s390_r0, ins->inst_imm);
3381 s390_msr (code, ins->dreg, s390_r0);
3383 break;
3384 case OP_IMUL_OVF: {
3385 short int *o[2];
3386 s390_ltr (code, s390_r1, ins->sreg1);
3387 s390_jz (code, 0); CODEPTR(code, o[0]);
3388 s390_ltr (code, s390_r0, ins->sreg2);
3389 s390_jnz (code, 6);
3390 s390_lhi (code, s390_r1, 0);
3391 s390_j (code, 0); CODEPTR(code, o[1]);
3392 s390_xr (code, s390_r0, s390_r1);
3393 s390_msr (code, s390_r1, ins->sreg2);
3394 s390_xr (code, s390_r0, s390_r1);
3395 s390_srl (code, s390_r0, 0, 31);
3396 s390_ltr (code, s390_r0, s390_r0);
3397 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_NZ, "OverflowException");
3398 PTRSLOT (code, o[0]);
3399 PTRSLOT (code, o[1]);
3400 s390_lgfr (code, ins->dreg, s390_r1);
3402 break;
3403 case OP_IMUL_OVF_UN: {
3404 s390_lhi (code, s390_r0, 0);
3405 s390_lr (code, s390_r1, ins->sreg1);
3406 s390_mlr (code, s390_r0, ins->sreg2);
3407 s390_ltr (code, s390_r0, s390_r0);
3408 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_NZ, "OverflowException");
3409 s390_lgfr (code, ins->dreg, s390_r1);
3411 break;
3412 case OP_ICONST:
3413 case OP_I8CONST: {
3414 S390_SET (code, ins->dreg, ins->inst_c0);
3416 break;
3417 case OP_AOTCONST: {
3418 mono_add_patch_info (cfg, code - cfg->native_code,
3419 (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3420 S390_LOAD_TEMPLATE (code, ins->dreg);
3422 break;
3423 case OP_JUMP_TABLE: {
3424 mono_add_patch_info (cfg, code - cfg->native_code,
3425 (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3426 S390_LOAD_TEMPLATE (code, ins->dreg);
3428 break;
3429 case OP_MOVE:
3430 if (ins->dreg != ins->sreg1) {
3431 s390_lgr (code, ins->dreg, ins->sreg1);
3433 break;
3434 case OP_LCONV_TO_I:
3435 case OP_LCONV_TO_I8:
3436 case OP_SEXT_I4:
3437 s390_lgfr (code, ins->dreg, ins->sreg1);
3438 break;
3439 case OP_LCONV_TO_I4:
3440 s390_lgfr (code, ins->dreg, ins->sreg1);
3441 break;
3442 case OP_LCONV_TO_U:
3443 case OP_LCONV_TO_U8:
3444 case OP_LCONV_TO_U4:
3445 case OP_ZEXT_I4:
3446 s390_llgfr (code, ins->dreg, ins->sreg1);
3447 break;
3448 case OP_LCONV_TO_OVF_U4:
3449 S390_SET (code, s390_r0, 4294967295);
3450 s390_clgr (code, ins->sreg1, s390_r0);
3451 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_GT, "OverflowException");
3452 s390_ltgr (code, ins->sreg1, ins->sreg1);
3453 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_LT, "OverflowException");
3454 s390_llgfr(code, ins->dreg, ins->sreg1);
3455 break;
3456 case OP_LCONV_TO_OVF_I4_UN:
3457 S390_SET (code, s390_r0, 2147483647);
3458 s390_cgr (code, ins->sreg1, s390_r0);
3459 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_GT, "OverflowException");
3460 s390_ltgr (code, ins->sreg1, ins->sreg1);
3461 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_LT, "OverflowException");
3462 s390_lgfr (code, ins->dreg, ins->sreg1);
3463 break;
3464 case OP_FMOVE:
3465 if (ins->dreg != ins->sreg1) {
3466 s390_ldr (code, ins->dreg, ins->sreg1);
3468 break;
3469 case OP_MOVE_F_TO_I8:
3470 s390_lgdr (code, ins->dreg, ins->sreg1);
3471 break;
3472 case OP_MOVE_I8_TO_F:
3473 s390_ldgr (code, ins->dreg, ins->sreg1);
3474 break;
3475 case OP_MOVE_F_TO_I4:
3476 s390_ledbr (code, s390_f0, ins->sreg1);
3477 s390_lgdr (code, ins->dreg, s390_f0);
3478 s390_srag (code, ins->dreg, ins->dreg, 0, 32);
3479 break;
3480 case OP_MOVE_I4_TO_F:
3481 s390_slag (code, s390_r0, ins->sreg1, 0, 32);
3482 s390_ldgr (code, ins->dreg, s390_r0);
3483 if (!cfg->r4fp)
3484 s390_ldebr (code, ins->dreg, ins->dreg);
3485 break;
3486 case OP_FCONV_TO_R4:
3487 s390_ledbr (code, ins->dreg, ins->sreg1);
3488 if (!cfg->r4fp)
3489 s390_ldebr (code, ins->dreg, ins->dreg);
3490 break;
3491 case OP_S390_SETF4RET:
3492 if (!cfg->r4fp)
3493 s390_ledbr (code, ins->dreg, ins->sreg1);
3494 break;
3495 case OP_TLS_GET: {
3496 if (s390_is_imm16 (ins->inst_offset)) {
3497 s390_lghi (code, s390_r13, ins->inst_offset);
3498 } else if (s390_is_imm32 (ins->inst_offset)) {
3499 s390_lgfi (code, s390_r13, ins->inst_offset);
3500 } else {
3501 S390_SET (code, s390_r13, ins->inst_offset);
3503 s390_ear (code, s390_r1, 0);
3504 s390_sllg(code, s390_r1, s390_r1, 0, 32);
3505 s390_ear (code, s390_r1, 1);
3506 s390_lg (code, ins->dreg, s390_r13, s390_r1, 0);
3508 break;
3509 case OP_TLS_SET: {
3510 if (s390_is_imm16 (ins->inst_offset)) {
3511 s390_lghi (code, s390_r13, ins->inst_offset);
3512 } else if (s390_is_imm32 (ins->inst_offset)) {
3513 s390_lgfi (code, s390_r13, ins->inst_offset);
3514 } else {
3515 S390_SET (code, s390_r13, ins->inst_offset);
3517 s390_ear (code, s390_r1, 0);
3518 s390_sllg(code, s390_r1, s390_r1, 0, 32);
3519 s390_ear (code, s390_r1, 1);
3520 s390_stg (code, ins->sreg1, s390_r13, s390_r1, 0);
3522 break;
3523 case OP_TAILCALL_PARAMETER :
3524 // This opcode helps compute sizes, i.e.
3525 // of the subsequent OP_TAILCALL, but contributes no code.
3526 g_assert (ins->next);
3527 break;
3528 case OP_TAILCALL :
3529 case OP_TAILCALL_MEMBASE : {
3530 MonoCallInst *call = (MonoCallInst *) ins;
3531 MonoMethod *method = call->method;
3532 MonoMethodSignature *sig = mono_method_signature_internal (method);
3533 CallInfo *cinfo = get_call_info (NULL, sig);
3534 int32_t stackUsage = (cinfo->sz.stack_size - S390_MINIMAL_STACK_SIZE),
3535 stackOffset = S390_MINIMAL_STACK_SIZE;
3537 if (cfg->method->save_lmf)
3538 restoreLMF(code, cfg->frame_reg, cfg->stack_usage);
3540 s390_lgr (code, s390_r12, cfg->frame_reg);
3541 code = backUpStackPtr(cfg, code);
3543 while (stackUsage > 256) {
3544 s390_mvc (code, 256, STK_BASE, stackOffset,
3545 s390_r12, stackOffset);
3546 stackUsage -= 256;
3547 stackOffset += 256;
3550 if (stackUsage > 0)
3551 s390_mvc (code, stackUsage, STK_BASE, stackOffset,
3552 s390_r12, stackOffset);
3554 s390_lmg (code, s390_r6, s390_r13, STK_BASE, S390_REG_SAVE_OFFSET);
3556 if (cfg->arch.used_fp_regs != 0) {
3557 int32_t fpOffset = sizeof(double);
3558 for (int i=8; i<16; i++) {
3559 if (cfg->arch.used_fp_regs & (1 << i)) {
3560 s390_ld (code, i, cfg->arch.fpSize, STK_BASE, fpOffset);
3561 fpOffset += sizeof(double);
3566 s390_lg (code, s390_r14, 0, STK_BASE, S390_RET_ADDR_OFFSET);
3567 if (ins->opcode == OP_TAILCALL_MEMBASE) {
3568 if (mono_hwcap_s390x_has_mie2) {
3569 s390_bi (code, 0, ins->sreg1, ins->inst_offset);
3570 } else {
3571 s390_lg (code, s390_r1, 0, ins->sreg1, ins->inst_offset);
3572 s390_br (code, s390_r1);
3574 } else {
3575 mono_add_patch_info (cfg, code - cfg->native_code,
3576 MONO_PATCH_INFO_METHOD_JUMP,
3577 call->method);
3578 s390_jcl (code, S390_CC_UN, 0);
3581 g_free (cinfo);
3583 break;
3584 case OP_CHECK_THIS: {
3585 /* ensure ins->sreg1 is not NULL */
3586 s390_lg (code, s390_r0, 0, ins->sreg1, 0);
3587 s390_ltgr (code, s390_r0, s390_r0);
3588 // EMIT_COND_SYSTEM_EXCEPTION (S390_CC_ZR, "NullReferenceException");
3590 break;
3591 case OP_ARGLIST: {
3592 const int offset = cfg->sig_cookie + cfg->stack_usage;
3594 if (s390_is_imm16 (offset)) {
3595 s390_lghi (code, s390_r0, offset);
3596 } else if (s390_is_imm32 (offset)) {
3597 s390_lgfi (code, s390_r0, offset);
3598 } else {
3599 S390_SET (code, s390_r0, offset);
3601 s390_agr (code, s390_r0, cfg->frame_reg);
3602 s390_stg (code, s390_r0, 0, ins->sreg1, 0);
3604 break;
3605 case OP_FCALL: {
3606 call = (MonoCallInst*)ins;
3608 mono_call_add_patch_info (cfg, call, code - cfg->native_code);
3609 S390_CALL_TEMPLATE (code, s390_r14);
3610 if (!cfg->r4fp && call->signature->ret->type == MONO_TYPE_R4)
3611 s390_ldebr (code, s390_f0, s390_f0);
3613 break;
3614 case OP_LCALL:
3615 case OP_VCALL:
3616 case OP_VCALL2:
3617 case OP_VOIDCALL:
3618 case OP_RCALL:
3619 case OP_CALL: {
3620 call = (MonoCallInst*)ins;
3621 mono_call_add_patch_info (cfg, call, code - cfg->native_code);
3622 S390_CALL_TEMPLATE (code, s390_r14);
3624 break;
3625 case OP_FCALL_REG: {
3626 call = (MonoCallInst*)ins;
3627 s390_lgr (code, s390_r1, ins->sreg1);
3628 s390_basr (code, s390_r14, s390_r1);
3629 if (!cfg->r4fp && call->signature->ret->type == MONO_TYPE_R4)
3630 s390_ldebr (code, s390_f0, s390_f0);
3632 break;
3633 case OP_LCALL_REG:
3634 case OP_VCALL_REG:
3635 case OP_VCALL2_REG:
3636 case OP_VOIDCALL_REG:
3637 case OP_RCALL_REG:
3638 case OP_CALL_REG: {
3639 s390_lgr (code, s390_r1, ins->sreg1);
3640 s390_basr (code, s390_r14, s390_r1);
3642 break;
3643 case OP_FCALL_MEMBASE: {
3644 call = (MonoCallInst*)ins;
3645 s390_lg (code, s390_r1, 0, ins->sreg1, ins->inst_offset);
3646 s390_basr (code, s390_r14, s390_r1);
3647 if (!cfg->r4fp && call->signature->ret->type == MONO_TYPE_R4)
3648 s390_ldebr (code, s390_f0, s390_f0);
3650 break;
3651 case OP_LCALL_MEMBASE:
3652 case OP_VCALL_MEMBASE:
3653 case OP_VCALL2_MEMBASE:
3654 case OP_VOIDCALL_MEMBASE:
3655 case OP_RCALL_MEMBASE:
3656 case OP_CALL_MEMBASE: {
3657 s390_lg (code, s390_r1, 0, ins->sreg1, ins->inst_offset);
3658 s390_basr (code, s390_r14, s390_r1);
3660 break;
3661 case OP_LOCALLOC: {
3662 int alloca_skip;
3663 int area_offset;
3665 if (cfg->param_area == 0)
3666 alloca_skip = S390_MINIMAL_STACK_SIZE;
3667 else
3668 alloca_skip = cfg->param_area;
3670 area_offset = S390_ALIGN(alloca_skip, S390_STACK_ALIGNMENT);
3671 s390_lgr (code, s390_r1, ins->sreg1);
3672 if (ins->flags & MONO_INST_INIT)
3673 s390_lgr (code, s390_r0, ins->sreg1);
3674 s390_aghi (code, s390_r1, 14);
3675 s390_srlg (code, s390_r1, s390_r1, 0, 3);
3676 s390_sllg (code, s390_r1, s390_r1, 0, 3);
3677 if (cfg->method->save_lmf) {
3678 /*----------------------------------*/
3679 /* we have to adjust lmf ebp value */
3680 /*----------------------------------*/
3681 int lmfOffset = cfg->stack_usage - sizeof(MonoLMF);
3683 s390_lgr (code, s390_r13, cfg->frame_reg);
3684 if (s390_is_imm16(lmfOffset)) {
3685 s390_aghi (code, s390_r13, lmfOffset);
3686 } else if (s390_is_imm32(lmfOffset)) {
3687 s390_agfi (code, s390_r13, lmfOffset);
3688 } else {
3689 S390_SET (code, s390_r13, lmfOffset);
3691 s390_lgr (code, s390_r14, STK_BASE);
3692 s390_sgr (code, s390_r14, s390_r1);
3693 s390_stg (code, s390_r14, 0, s390_r13,
3694 G_STRUCT_OFFSET(MonoLMF, ebp));
3696 s390_lg (code, s390_r13, 0, STK_BASE, 0);
3697 s390_sgr (code, STK_BASE, s390_r1);
3698 s390_stg (code, s390_r13, 0, STK_BASE, 0);
3699 s390_la (code, ins->dreg, 0, STK_BASE, area_offset);
3700 s390_srlg (code, ins->dreg, ins->dreg, 0, 3);
3701 s390_sllg (code, ins->dreg, ins->dreg, 0, 3);
3702 if (ins->flags & MONO_INST_INIT) {
3703 s390_lgr (code, s390_r1, s390_r0);
3704 s390_lgr (code, s390_r0, ins->dreg);
3705 s390_lgr (code, s390_r14, s390_r12);
3706 s390_lghi (code, s390_r13, 0);
3707 s390_mvcle(code, s390_r0, s390_r12, 0, 0);
3708 s390_jo (code, -2);
3709 s390_lgr (code, s390_r12, s390_r14);
3712 break;
3713 case OP_THROW: {
3714 s390_lgr (code, s390_r2, ins->sreg1);
3715 mono_add_patch_info (cfg, code-cfg->native_code, MONO_PATCH_INFO_JIT_ICALL_ID,
3716 GUINT_TO_POINTER (MONO_JIT_ICALL_mono_arch_throw_exception));
3717 S390_CALL_TEMPLATE(code, s390_r14);
3719 break;
3720 case OP_RETHROW: {
3721 s390_lgr (code, s390_r2, ins->sreg1);
3722 mono_add_patch_info (cfg, code-cfg->native_code, MONO_PATCH_INFO_JIT_ICALL_ID,
3723 GUINT_TO_POINTER (MONO_JIT_ICALL_mono_arch_rethrow_exception));
3724 S390_CALL_TEMPLATE(code, s390_r14);
3726 break;
3727 case OP_START_HANDLER: {
3728 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3730 S390_LONG (code, stg, stg, s390_r14, 0,
3731 spvar->inst_basereg,
3732 spvar->inst_offset);
3734 break;
3735 case OP_ENDFILTER: {
3736 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3738 if (ins->sreg1 != s390_r2)
3739 s390_lgr(code, s390_r2, ins->sreg1);
3740 S390_LONG (code, lg, lg, s390_r14, 0,
3741 spvar->inst_basereg,
3742 spvar->inst_offset);
3743 s390_br (code, s390_r14);
3745 break;
3746 case OP_ENDFINALLY: {
3747 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3749 S390_LONG (code, lg, lg, s390_r14, 0,
3750 spvar->inst_basereg,
3751 spvar->inst_offset);
3752 s390_br (code, s390_r14);
3754 break;
3755 case OP_CALL_HANDLER: {
3756 mono_add_patch_info (cfg, code-cfg->native_code,
3757 MONO_PATCH_INFO_BB, ins->inst_target_bb);
3758 s390_brasl (code, s390_r14, 0);
3759 for (GList *tmp = ins->inst_eh_blocks; tmp != bb->clause_holes; tmp = tmp->prev)
3760 mono_cfg_add_try_hole (cfg, ((MonoLeaveClause *) tmp->data)->clause, code, bb);
3762 break;
3763 case OP_LABEL: {
3764 ins->inst_c0 = code - cfg->native_code;
3766 break;
3767 case OP_RELAXED_NOP:
3768 case OP_NOP:
3769 case OP_DUMMY_USE:
3770 case OP_DUMMY_ICONST:
3771 case OP_DUMMY_I8CONST:
3772 case OP_DUMMY_R8CONST:
3773 case OP_DUMMY_R4CONST:
3774 case OP_NOT_REACHED:
3775 case OP_NOT_NULL: {
3777 break;
3778 case OP_IL_SEQ_POINT:
3779 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3780 break;
3781 case OP_SEQ_POINT: {
3782 int i;
3784 if (cfg->compile_aot)
3785 NOT_IMPLEMENTED;
3788 * Read from the single stepping trigger page. This will cause a
3789 * SIGSEGV when single stepping is enabled.
3790 * We do this _before_ the breakpoint, so single stepping after
3791 * a breakpoint is hit will step to the next IL offset.
3793 if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
3794 breakpointCode.pTrigger = ss_trigger_page;
3795 memcpy(code, (void *) &breakpointCode, BREAKPOINT_SIZE);
3796 code += BREAKPOINT_SIZE;
3799 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3802 * A placeholder for a possible breakpoint inserted by
3803 * mono_arch_set_breakpoint ().
3805 for (i = 0; i < (BREAKPOINT_SIZE / S390X_NOP_SIZE); ++i)
3806 s390_nop (code);
3809 * Add an additional nop so skipping the bp doesn't cause the ip to point
3810 * to another IL offset.
3812 s390_nop (code);
3814 break;
3816 case OP_GENERIC_CLASS_INIT: {
3817 static int byte_offset = -1;
3818 static guint8 bitmask;
3819 short int *jump;
3821 g_assert (ins->sreg1 == S390_FIRST_ARG_REG);
3823 if (byte_offset < 0)
3824 mono_marshal_find_bitfield_offset (MonoVTable, initialized, &byte_offset, &bitmask);
3826 s390_tm (code, ins->sreg1, byte_offset, bitmask);
3827 s390_jo (code, 0); CODEPTR(code, jump);
3829 mono_add_patch_info (cfg, code-cfg->native_code, MONO_PATCH_INFO_JIT_ICALL_ID,
3830 GUINT_TO_POINTER (MONO_JIT_ICALL_mono_generic_class_init));
3831 S390_CALL_TEMPLATE(code, s390_r14);
3833 PTRSLOT (code, jump);
3835 ins->flags |= MONO_INST_GC_CALLSITE;
3836 ins->backend.pc_offset = code - cfg->native_code;
3837 break;
3839 case OP_BR:
3840 EMIT_UNCOND_BRANCH(ins);
3841 break;
3842 case OP_BR_REG: {
3843 s390_br (code, ins->sreg1);
3845 break;
3846 case OP_CEQ:
3847 case OP_ICEQ:
3848 case OP_LCEQ: {
3849 s390_lghi(code, ins->dreg, 1);
3850 s390_jz (code, 4);
3851 s390_lghi(code, ins->dreg, 0);
3853 break;
3854 case OP_CLT:
3855 case OP_ICLT:
3856 case OP_LCLT: {
3857 s390_lghi(code, ins->dreg, 1);
3858 s390_jl (code, 4);
3859 s390_lghi(code, ins->dreg, 0);
3861 break;
3862 case OP_CLT_UN:
3863 case OP_ICLT_UN:
3864 case OP_LCLT_UN: {
3865 s390_lghi(code, ins->dreg, 1);
3866 s390_jlo (code, 4);
3867 s390_lghi(code, ins->dreg, 0);
3869 break;
3870 case OP_CGT:
3871 case OP_ICGT:
3872 case OP_LCGT: {
3873 s390_lghi(code, ins->dreg, 1);
3874 s390_jh (code, 4);
3875 s390_lghi(code, ins->dreg, 0);
3877 break;
3878 case OP_CGT_UN:
3879 case OP_ICGT_UN:
3880 case OP_LCGT_UN: {
3881 s390_lghi(code, ins->dreg, 1);
3882 s390_jho (code, 4);
3883 s390_lghi(code, ins->dreg, 0);
3885 break;
3886 case OP_ICNEQ: {
3887 s390_lghi(code, ins->dreg, 1);
3888 s390_jne (code, 4);
3889 s390_lghi(code, ins->dreg, 0);
3891 break;
3892 case OP_ICGE: {
3893 s390_lghi(code, ins->dreg, 1);
3894 s390_jhe (code, 4);
3895 s390_lghi(code, ins->dreg, 0);
3897 break;
3898 case OP_ICLE: {
3899 s390_lghi(code, ins->dreg, 1);
3900 s390_jle (code, 4);
3901 s390_lghi(code, ins->dreg, 0);
3903 break;
3904 case OP_ICGE_UN: {
3905 s390_lghi(code, ins->dreg, 1);
3906 s390_jhe (code, 4);
3907 s390_lghi(code, ins->dreg, 0);
3909 break;
3910 case OP_ICLE_UN: {
3911 s390_lghi(code, ins->dreg, 1);
3912 s390_jle (code, 4);
3913 s390_lghi(code, ins->dreg, 0);
3915 break;
3916 case OP_COND_EXC_EQ:
3917 case OP_COND_EXC_IEQ:
3918 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_EQ, ins->inst_p1);
3919 break;
3920 case OP_COND_EXC_NE_UN:
3921 case OP_COND_EXC_INE_UN:
3922 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_NE, ins->inst_p1);
3923 break;
3924 case OP_COND_EXC_LT:
3925 case OP_COND_EXC_ILT:
3926 case OP_COND_EXC_LT_UN:
3927 case OP_COND_EXC_ILT_UN:
3928 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_LT, ins->inst_p1);
3929 break;
3930 case OP_COND_EXC_GT:
3931 case OP_COND_EXC_IGT:
3932 case OP_COND_EXC_GT_UN:
3933 case OP_COND_EXC_IGT_UN:
3934 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_GT, ins->inst_p1);
3935 break;
3936 case OP_COND_EXC_GE:
3937 case OP_COND_EXC_IGE:
3938 case OP_COND_EXC_GE_UN:
3939 case OP_COND_EXC_IGE_UN:
3940 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_GE, ins->inst_p1);
3941 break;
3942 case OP_COND_EXC_LE:
3943 case OP_COND_EXC_ILE:
3944 case OP_COND_EXC_LE_UN:
3945 case OP_COND_EXC_ILE_UN:
3946 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_LE, ins->inst_p1);
3947 break;
3948 case OP_COND_EXC_OV:
3949 case OP_COND_EXC_IOV:
3950 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_OV, ins->inst_p1);
3951 break;
3952 case OP_COND_EXC_NO:
3953 case OP_COND_EXC_INO:
3954 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_NO, ins->inst_p1);
3955 break;
3956 case OP_COND_EXC_C:
3957 case OP_COND_EXC_IC:
3958 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_CY, ins->inst_p1);
3959 break;
3960 case OP_COND_EXC_NC:
3961 case OP_COND_EXC_INC:
3962 EMIT_COND_SYSTEM_EXCEPTION (S390_CC_NC, ins->inst_p1);
3963 break;
3964 case OP_LBEQ:
3965 case OP_IBEQ:
3966 EMIT_COND_BRANCH (ins, S390_CC_EQ);
3967 break;
3968 case OP_LBNE_UN:
3969 case OP_IBNE_UN:
3970 EMIT_COND_BRANCH (ins, S390_CC_NE);
3971 break;
3972 case OP_LBLT:
3973 case OP_LBLT_UN:
3974 case OP_IBLT:
3975 case OP_IBLT_UN:
3976 EMIT_COND_BRANCH (ins, S390_CC_LT);
3977 break;
3978 case OP_LBGT:
3979 case OP_LBGT_UN:
3980 case OP_IBGT:
3981 case OP_IBGT_UN:
3982 EMIT_COND_BRANCH (ins, S390_CC_GT);
3983 break;
3984 case OP_LBGE:
3985 case OP_LBGE_UN:
3986 case OP_IBGE:
3987 case OP_IBGE_UN:
3988 EMIT_COND_BRANCH (ins, S390_CC_GE);
3989 break;
3990 case OP_LBLE:
3991 case OP_LBLE_UN:
3992 case OP_IBLE:
3993 case OP_IBLE_UN:
3994 EMIT_COND_BRANCH (ins, S390_CC_LE);
3995 break;
3997 case OP_S390_CRJ:
3998 EMIT_COMP_AND_BRANCH(ins, crj, cr);
3999 break;
4001 case OP_S390_CLRJ:
4002 EMIT_COMP_AND_BRANCH(ins, clrj, clr);
4003 break;
4005 case OP_S390_CGRJ:
4006 EMIT_COMP_AND_BRANCH(ins, cgrj, cgr);
4007 break;
4009 case OP_S390_CLGRJ:
4010 EMIT_COMP_AND_BRANCH(ins, clgrj, clgr);
4011 break;
4013 case OP_S390_CIJ:
4014 EMIT_COMP_AND_BRANCH_IMM(ins, crj, cr, ltr, FALSE);
4015 break;
4017 case OP_S390_CLIJ:
4018 EMIT_COMP_AND_BRANCH_IMM(ins, clrj, clr, ltr, TRUE);
4019 break;
4021 case OP_S390_CGIJ:
4022 EMIT_COMP_AND_BRANCH_IMM(ins, cgrj, cgr, ltgr, FALSE);
4023 break;
4025 case OP_S390_CLGIJ:
4026 EMIT_COMP_AND_BRANCH_IMM(ins, clgrj, clgr, ltgr, TRUE);
4027 break;
4029 /* floating point opcodes */
4030 case OP_R8CONST: {
4031 if (*((double *) ins->inst_p0) == 0) {
4032 s390_lzdr (code, ins->dreg);
4033 } else {
4034 S390_SET (code, s390_r13, ins->inst_p0);
4035 s390_ld (code, ins->dreg, 0, s390_r13, 0);
4038 break;
4039 case OP_R4CONST: {
4040 if (*((float *) ins->inst_p0) == 0) {
4041 if (cfg->r4fp)
4042 s390_lzer (code, ins->dreg);
4043 else
4044 s390_lzdr (code, ins->dreg);
4045 } else {
4046 S390_SET (code, s390_r13, ins->inst_p0);
4047 if (cfg->r4fp) {
4048 S390_LONG (code, ley, le, ins->dreg, 0, s390_r13, 0);
4049 } else {
4050 s390_ldeb (code, ins->dreg, 0, s390_r13, 0);
4054 break;
4055 case OP_STORER8_MEMBASE_REG: {
4056 S390_LONG (code, stdy, std, ins->sreg1, 0,
4057 ins->inst_destbasereg, ins->inst_offset);
4059 break;
4060 case OP_LOADR8_MEMBASE: {
4061 S390_LONG (code, ldy, ld, ins->dreg, 0,
4062 ins->inst_basereg, ins->inst_offset);
4064 break;
4065 case OP_STORER4_MEMBASE_REG: {
4066 if (cfg->r4fp) {
4067 S390_LONG (code, stey, ste, ins->sreg1, 0,
4068 ins->inst_destbasereg, ins->inst_offset);
4069 } else {
4070 s390_ledbr (code, s390_f15, ins->sreg1);
4071 S390_LONG (code, stey, ste, s390_f15, 0,
4072 ins->inst_destbasereg, ins->inst_offset);
4075 break;
4076 case OP_LOADR4_MEMBASE: {
4077 if (cfg->r4fp) {
4078 S390_LONG (code, ley, le, ins->dreg, 0,
4079 ins->inst_basereg, ins->inst_offset);
4080 } else {
4081 S390_LONG (code, ley, le, s390_f15, 0,
4082 ins->inst_basereg, ins->inst_offset);
4083 s390_ldebr (code, ins->dreg, s390_f15);
4086 break;
4087 case OP_ICONV_TO_R_UN: {
4088 if (mono_hwcap_s390x_has_fpe) {
4089 s390_cdlfbr (code, ins->dreg, 5, ins->sreg1, 0);
4090 } else {
4091 s390_llgfr (code, s390_r0, ins->sreg1);
4092 s390_cdgbr (code, ins->dreg, s390_r0);
4095 break;
4096 case OP_LCONV_TO_R_UN: {
4097 if (mono_hwcap_s390x_has_fpe) {
4098 s390_cdlgbr (code, ins->dreg, 5, ins->sreg1, 0);
4099 } else {
4100 short int *jump;
4101 s390_cxgbr (code, s390_f12, ins->sreg1);
4102 s390_ltgr (code, ins->sreg1, ins->sreg1);
4103 s390_jnl (code, 0); CODEPTR(code, jump);
4104 S390_SET (code, s390_r13, 0x403f000000000000llu);
4105 s390_lgdr (code, s390_f13, s390_r13);
4106 s390_lzdr (code, s390_f15);
4107 s390_axbr (code, s390_f12, s390_f13);
4108 PTRSLOT(code, jump);
4109 s390_ldxbr (code, s390_f13, s390_f12);
4110 s390_ldr (code, ins->dreg, s390_f13);
4113 break;
4114 case OP_LCONV_TO_R4:
4115 case OP_ICONV_TO_R4: {
4116 s390_cegbr (code, ins->dreg, ins->sreg1);
4117 if (!cfg->r4fp)
4118 s390_ldebr (code, ins->dreg, ins->dreg);
4120 break;
4121 case OP_LCONV_TO_R8:
4122 case OP_ICONV_TO_R8: {
4123 s390_cdgbr (code, ins->dreg, ins->sreg1);
4125 break;
4126 case OP_FCONV_TO_I1:
4127 s390_cgdbr (code, ins->dreg, 5, ins->sreg1);
4128 s390_ltgr (code, ins->dreg, ins->dreg);
4129 s390_jnl (code, 4);
4130 s390_oill (code, ins->dreg, 0x80);
4131 s390_lghi (code, s390_r0, 0xff);
4132 s390_ngr (code, ins->dreg, s390_r0);
4133 break;
4134 case OP_FCONV_TO_U1:
4135 if (mono_hwcap_s390x_has_fpe) {
4136 s390_clgdbr (code, ins->dreg, 5, ins->sreg1, 0);
4137 s390_lghi (code, s390_r0, 0xff);
4138 s390_ngr (code, ins->dreg, s390_r0);
4139 } else {
4140 code = emit_double_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4142 break;
4143 case OP_FCONV_TO_I2:
4144 s390_cgdbr (code, ins->dreg, 5, ins->sreg1);
4145 s390_ltgr (code, ins->dreg, ins->dreg);
4146 s390_jnl (code, 4);
4147 s390_oill (code, ins->dreg, 0x8000);
4148 s390_llill (code, s390_r0, 0xffff);
4149 s390_ngr (code, ins->dreg, s390_r0);
4150 break;
4151 case OP_FCONV_TO_U2:
4152 if (mono_hwcap_s390x_has_fpe) {
4153 s390_clgdbr (code, ins->dreg, 5, ins->sreg1, 0);
4154 s390_llill (code, s390_r0, 0xffff);
4155 s390_ngr (code, ins->dreg, s390_r0);
4156 } else {
4157 code = emit_double_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4159 break;
4160 case OP_FCONV_TO_I4:
4161 case OP_FCONV_TO_I:
4162 s390_cfdbr (code, ins->dreg, 5, ins->sreg1);
4163 break;
4164 case OP_FCONV_TO_U4:
4165 case OP_FCONV_TO_U:
4166 if (mono_hwcap_s390x_has_fpe) {
4167 s390_clfdbr (code, ins->dreg, 5, ins->sreg1, 0);
4168 } else {
4169 code = emit_double_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4171 break;
4172 case OP_FCONV_TO_I8:
4173 s390_cgdbr (code, ins->dreg, 5, ins->sreg1);
4174 break;
4175 case OP_FCONV_TO_U8:
4176 if (mono_hwcap_s390x_has_fpe) {
4177 s390_clgdbr (code, ins->dreg, 5, ins->sreg1, 0);
4178 } else {
4179 code = emit_double_to_int (cfg, code, ins->dreg, ins->sreg1, 8, FALSE);
4181 break;
4182 case OP_RCONV_TO_I1:
4183 s390_cgebr (code, ins->dreg, 5, ins->sreg1);
4184 s390_ltgr (code, ins->dreg, ins->dreg);
4185 s390_jnl (code, 4);
4186 s390_oill (code, ins->dreg, 0x80);
4187 s390_lghi (code, s390_r0, 0xff);
4188 s390_ngr (code, ins->dreg, s390_r0);
4189 break;
4190 case OP_RCONV_TO_U1:
4191 if (mono_hwcap_s390x_has_fpe) {
4192 s390_clgebr (code, ins->dreg, 5, ins->sreg1, 0);
4193 s390_lghi (code, s390_r0, 0xff);
4194 s390_ngr (code, ins->dreg, s390_r0);
4195 } else {
4196 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4198 break;
4199 case OP_RCONV_TO_I2:
4200 s390_cgebr (code, ins->dreg, 5, ins->sreg1);
4201 s390_ltgr (code, ins->dreg, ins->dreg);
4202 s390_jnl (code, 4);
4203 s390_oill (code, ins->dreg, 0x8000);
4204 s390_llill (code, s390_r0, 0xffff);
4205 s390_ngr (code, ins->dreg, s390_r0);
4206 break;
4207 case OP_RCONV_TO_U2:
4208 if (mono_hwcap_s390x_has_fpe) {
4209 s390_clgebr (code, ins->dreg, 5, ins->sreg1, 0);
4210 s390_llill (code, s390_r0, 0xffff);
4211 s390_ngr (code, ins->dreg, s390_r0);
4212 } else {
4213 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4215 break;
4216 case OP_RCONV_TO_I4:
4217 case OP_RCONV_TO_I:
4218 s390_cfebr (code, ins->dreg, 5, ins->sreg1);
4219 break;
4220 case OP_RCONV_TO_U4:
4221 if (mono_hwcap_s390x_has_fpe) {
4222 s390_clfebr (code, ins->dreg, 5, ins->sreg1, 0);
4223 } else {
4224 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4226 break;
4227 case OP_RCONV_TO_I8:
4228 s390_cgebr (code, ins->dreg, 5, ins->sreg1);
4229 break;
4230 case OP_RCONV_TO_U8:
4231 if (mono_hwcap_s390x_has_fpe) {
4232 s390_clgebr (code, ins->dreg, 5, ins->sreg1, 0);
4233 } else {
4234 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 8, FALSE);
4236 break;
4237 case OP_LCONV_TO_OVF_I: {
4238 /* Valid ints: 0xffffffff:8000000 to 00000000:0x7f000000 */
4239 short int *o[5];
4240 s390_ltgr (code, ins->sreg2, ins->sreg2);
4241 s390_jnl (code, 0); CODEPTR(code, o[0]);
4242 s390_ltgr (code, ins->sreg1, ins->sreg1);
4243 s390_jnl (code, 0); CODEPTR(code, o[1]);
4244 s390_lhi (code, s390_r13, -1);
4245 s390_cgr (code, ins->sreg1, s390_r13);
4246 s390_jnz (code, 0); CODEPTR(code, o[2]);
4247 if (ins->dreg != ins->sreg2)
4248 s390_lgr (code, ins->dreg, ins->sreg2);
4249 s390_j (code, 0); CODEPTR(code, o[3]);
4250 PTRSLOT(code, o[0]);
4251 s390_jz (code, 0); CODEPTR(code, o[4]);
4252 PTRSLOT(code, o[1]);
4253 PTRSLOT(code, o[2]);
4254 mono_add_patch_info (cfg, code - cfg->native_code,
4255 MONO_PATCH_INFO_EXC, "OverflowException");
4256 s390_brasl (code, s390_r14, 0);
4257 PTRSLOT(code, o[3]);
4258 PTRSLOT(code, o[4]);
4260 break;
4261 case OP_ABS: {
4262 s390_lpdbr (code, ins->dreg, ins->sreg1);
4264 break;
4265 case OP_SQRT: {
4266 s390_sqdbr (code, ins->dreg, ins->sreg1);
4268 break;
4269 case OP_FADD: {
4270 CHECK_SRCDST_COM_F;
4271 s390_adbr (code, ins->dreg, src2);
4273 break;
4274 case OP_RADD: {
4275 CHECK_SRCDST_COM_F;
4276 s390_aebr (code, ins->dreg, src2);
4278 break;
4279 case OP_FSUB: {
4280 CHECK_SRCDST_NCOM_F;
4281 s390_sdbr (code, ins->dreg, src2);
4283 break;
4284 case OP_RSUB: {
4285 CHECK_SRCDST_NCOM_F;
4286 s390_sebr (code, ins->dreg, src2);
4288 break;
4289 case OP_FMUL: {
4290 CHECK_SRCDST_COM_F;
4291 s390_mdbr (code, ins->dreg, src2);
4293 break;
4294 case OP_RMUL: {
4295 CHECK_SRCDST_COM_F;
4296 s390_meer (code, ins->dreg, src2);
4298 break;
4299 case OP_FDIV: {
4300 CHECK_SRCDST_NCOM_F;
4301 s390_ddbr (code, ins->dreg, src2);
4303 break;
4304 case OP_RDIV: {
4305 CHECK_SRCDST_NCOM_F;
4306 s390_debr (code, ins->dreg, src2);
4308 break;
4309 case OP_FNEG: {
4310 s390_lcdbr (code, ins->dreg, ins->sreg1);
4312 break;
4313 case OP_RNEG: {
4314 s390_lcebr (code, ins->dreg, ins->sreg1);
4316 break;
4317 case OP_FREM: {
4318 CHECK_SRCDST_NCOM_F;
4319 s390_didbr (code, ins->dreg, src2, 5, s390_f15);
4321 break;
4322 case OP_RREM: {
4323 CHECK_SRCDST_NCOM_F;
4324 s390_diebr (code, ins->dreg, src2, 5, s390_f15);
4326 break;
4327 case OP_FCOMPARE: {
4328 s390_cdbr (code, ins->sreg1, ins->sreg2);
4330 break;
4331 case OP_RCOMPARE: {
4332 s390_cebr (code, ins->sreg1, ins->sreg2);
4334 break;
4335 case OP_FCEQ: {
4336 s390_cdbr (code, ins->sreg1, ins->sreg2);
4337 s390_lghi (code, ins->dreg, 1);
4338 s390_je (code, 4);
4339 s390_lghi (code, ins->dreg, 0);
4341 break;
4342 case OP_FCLT: {
4343 s390_cdbr (code, ins->sreg1, ins->sreg2);
4344 s390_lghi (code, ins->dreg, 1);
4345 s390_jl (code, 4);
4346 s390_lghi (code, ins->dreg, 0);
4348 break;
4349 case OP_FCLT_UN: {
4350 s390_cdbr (code, ins->sreg1, ins->sreg2);
4351 s390_lghi (code, ins->dreg, 1);
4352 s390_jlo (code, 4);
4353 s390_lghi (code, ins->dreg, 0);
4355 break;
4356 case OP_FCGT: {
4357 s390_cdbr (code, ins->sreg1, ins->sreg2);
4358 s390_lghi (code, ins->dreg, 1);
4359 s390_jh (code, 4);
4360 s390_lghi (code, ins->dreg, 0);
4362 break;
4363 case OP_FCGT_UN: {
4364 s390_cdbr (code, ins->sreg1, ins->sreg2);
4365 s390_lghi (code, ins->dreg, 1);
4366 s390_jho (code, 4);
4367 s390_lghi (code, ins->dreg, 0);
4369 break;
4370 case OP_FCNEQ: {
4371 s390_cdbr (code, ins->sreg1, ins->sreg2);
4372 s390_lghi (code, ins->dreg, 1);
4373 s390_jne (code, 4);
4374 s390_lghi (code, ins->dreg, 0);
4376 break;
4377 case OP_FCGE: {
4378 s390_cdbr (code, ins->sreg1, ins->sreg2);
4379 s390_lghi (code, ins->dreg, 1);
4380 s390_jhe (code, 4);
4381 s390_lghi (code, ins->dreg, 0);
4383 break;
4384 case OP_FCLE: {
4385 s390_cdbr (code, ins->sreg1, ins->sreg2);
4386 s390_lghi (code, ins->dreg, 1);
4387 s390_jle (code, 4);
4388 s390_lghi (code, ins->dreg, 0);
4390 break;
4391 case OP_RCEQ: {
4392 s390_cdbr (code, ins->sreg1, ins->sreg2);
4393 s390_lghi (code, ins->dreg, 1);
4394 s390_je (code, 4);
4395 s390_lghi (code, ins->dreg, 0);
4397 break;
4398 case OP_RCLT: {
4399 s390_cdbr (code, ins->sreg1, ins->sreg2);
4400 s390_lghi (code, ins->dreg, 1);
4401 s390_jl (code, 4);
4402 s390_lghi (code, ins->dreg, 0);
4404 break;
4405 case OP_RCLT_UN: {
4406 s390_cdbr (code, ins->sreg1, ins->sreg2);
4407 s390_lghi (code, ins->dreg, 1);
4408 s390_jlo (code, 4);
4409 s390_lghi (code, ins->dreg, 0);
4411 break;
4412 case OP_RCGT: {
4413 s390_cdbr (code, ins->sreg1, ins->sreg2);
4414 s390_lghi (code, ins->dreg, 1);
4415 s390_jh (code, 4);
4416 s390_lghi (code, ins->dreg, 0);
4418 break;
4419 case OP_RCGT_UN: {
4420 s390_cdbr (code, ins->sreg1, ins->sreg2);
4421 s390_lghi (code, ins->dreg, 1);
4422 s390_jho (code, 4);
4423 s390_lghi (code, ins->dreg, 0);
4425 break;
4426 case OP_RCNEQ: {
4427 s390_cdbr (code, ins->sreg1, ins->sreg2);
4428 s390_lghi (code, ins->dreg, 1);
4429 s390_jne (code, 4);
4430 s390_lghi (code, ins->dreg, 0);
4432 break;
4433 case OP_RCGE: {
4434 s390_cdbr (code, ins->sreg1, ins->sreg2);
4435 s390_lghi (code, ins->dreg, 1);
4436 s390_jhe (code, 4);
4437 s390_lghi (code, ins->dreg, 0);
4439 break;
4440 case OP_RCLE: {
4441 s390_cebr (code, ins->sreg1, ins->sreg2);
4442 s390_lghi (code, ins->dreg, 1);
4443 s390_jle (code, 4);
4444 s390_lghi (code, ins->dreg, 0);
4446 break;
4447 case OP_FBEQ: {
4448 short *o;
4449 s390_jo (code, 0); CODEPTR(code, o);
4450 EMIT_COND_BRANCH (ins, S390_CC_EQ);
4451 PTRSLOT (code, o);
4453 break;
4454 case OP_FBNE_UN:
4455 EMIT_COND_BRANCH (ins, S390_CC_NE|S390_CC_OV);
4456 break;
4457 case OP_FBLT: {
4458 short *o;
4459 s390_jo (code, 0); CODEPTR(code, o);
4460 EMIT_COND_BRANCH (ins, S390_CC_LT);
4461 PTRSLOT (code, o);
4463 break;
4464 case OP_FBLT_UN:
4465 EMIT_COND_BRANCH (ins, S390_CC_LT|S390_CC_OV);
4466 break;
4467 case OP_FBGT: {
4468 short *o;
4469 s390_jo (code, 0); CODEPTR(code, o);
4470 EMIT_COND_BRANCH (ins, S390_CC_GT);
4471 PTRSLOT (code, o);
4473 break;
4474 case OP_FBGT_UN:
4475 EMIT_COND_BRANCH (ins, S390_CC_GT|S390_CC_OV);
4476 break;
4477 case OP_FBGE: {
4478 short *o;
4479 s390_jo (code, 0); CODEPTR(code, o);
4480 EMIT_COND_BRANCH (ins, S390_CC_GE);
4481 PTRSLOT (code, o);
4483 break;
4484 case OP_FBGE_UN:
4485 EMIT_COND_BRANCH (ins, S390_CC_GE|S390_CC_OV);
4486 break;
4487 case OP_FBLE: {
4488 short *o;
4489 s390_jo (code, 0); CODEPTR(code, o);
4490 EMIT_COND_BRANCH (ins, S390_CC_LE);
4491 PTRSLOT (code, o);
4493 break;
4494 case OP_FBLE_UN:
4495 EMIT_COND_BRANCH (ins, S390_CC_LE|S390_CC_OV);
4496 break;
4497 case OP_CKFINITE: {
4498 short *o;
4499 s390_lhi (code, s390_r13, 0x7f);
4500 s390_tcdb (code, ins->sreg1, 0, s390_r13, 0);
4501 s390_jz (code, 0); CODEPTR(code, o);
4502 mono_add_patch_info (cfg, code - cfg->native_code,
4503 MONO_PATCH_INFO_EXC, "OverflowException");
4504 s390_brasl (code, s390_r14,0);
4505 PTRSLOT(code, o);
4507 break;
4508 case OP_S390_MOVE: {
4509 if (ins->backend.size > 0) {
4510 if (ins->backend.size <= 256) {
4511 s390_mvc (code, ins->backend.size, ins->dreg,
4512 ins->inst_offset, ins->sreg1, ins->inst_imm);
4513 } else {
4514 s390_lgr (code, s390_r0, ins->dreg);
4515 if (ins->inst_offset > 0) {
4516 if (s390_is_imm16 (ins->inst_offset)) {
4517 s390_aghi (code, s390_r0, ins->inst_offset);
4518 } else if (s390_is_imm32 (ins->inst_offset)) {
4519 s390_agfi (code, s390_r0, ins->inst_offset);
4520 } else {
4521 S390_SET (code, s390_r13, ins->inst_offset);
4522 s390_agr (code, s390_r0, s390_r13);
4525 s390_lgr (code, s390_r12, ins->sreg1);
4526 if (ins->inst_imm > 0) {
4527 if (s390_is_imm16 (ins->inst_imm)) {
4528 s390_aghi (code, s390_r12, ins->inst_imm);
4529 } else if (s390_is_imm32 (ins->inst_imm)) {
4530 s390_agfi (code, s390_r12, ins->inst_imm);
4531 } else {
4532 S390_SET (code, s390_r13, ins->inst_imm);
4533 s390_agr (code, s390_r12, s390_r13);
4536 if (s390_is_imm16 (ins->backend.size)) {
4537 s390_lghi (code, s390_r1, ins->backend.size);
4538 } else if (s390_is_imm32 (ins->inst_offset)) {
4539 s390_agfi (code, s390_r1, ins->backend.size);
4540 } else {
4541 S390_SET (code, s390_r13, ins->backend.size);
4542 s390_agr (code, s390_r1, s390_r13);
4544 s390_lgr (code, s390_r13, s390_r1);
4545 s390_mvcle(code, s390_r0, s390_r12, 0, 0);
4546 s390_jo (code, -2);
4550 break;
4551 case OP_ATOMIC_ADD_I8: {
4552 if (mono_hwcap_s390x_has_ia) {
4553 s390_laag (code, ins->dreg, ins->sreg2, ins->inst_basereg, ins->inst_offset);
4554 s390_agr (code, ins->dreg, ins->sreg2);
4555 } else {
4556 s390_lgr (code, s390_r1, ins->sreg2);
4557 s390_lg (code, s390_r0, 0, ins->inst_basereg, ins->inst_offset);
4558 s390_agr (code, s390_r1, s390_r0);
4559 s390_csg (code, s390_r0, s390_r1, ins->inst_basereg, ins->inst_offset);
4560 s390_jnz (code, -10);
4561 s390_lgr (code, ins->dreg, s390_r1);
4564 break;
4565 case OP_ATOMIC_EXCHANGE_I8: {
4566 s390_lg (code, s390_r0, 0, ins->inst_basereg, ins->inst_offset);
4567 s390_csg (code, s390_r0, ins->sreg2, ins->inst_basereg, ins->inst_offset);
4568 s390_jnz (code, -6);
4569 s390_lgr (code, ins->dreg, s390_r0);
4571 break;
4572 case OP_ATOMIC_ADD_I4: {
4573 if (mono_hwcap_s390x_has_ia) {
4574 s390_laa (code, ins->dreg, ins->sreg2, ins->inst_basereg, ins->inst_offset);
4575 s390_ar (code, ins->dreg, ins->sreg2);
4576 } else {
4577 s390_lgfr(code, s390_r1, ins->sreg2);
4578 s390_lgf (code, s390_r0, 0, ins->inst_basereg, ins->inst_offset);
4579 s390_agr (code, s390_r1, s390_r0);
4580 s390_cs (code, s390_r0, s390_r1, ins->inst_basereg, ins->inst_offset);
4581 s390_jnz (code, -9);
4582 s390_lgfr(code, ins->dreg, s390_r1);
4585 break;
4586 case OP_ATOMIC_EXCHANGE_I4: {
4587 s390_l (code, s390_r0, 0, ins->inst_basereg, ins->inst_offset);
4588 s390_cs (code, s390_r0, ins->sreg2, ins->inst_basereg, ins->inst_offset);
4589 s390_jnz (code, -4);
4590 s390_lgfr(code, ins->dreg, s390_r0);
4592 break;
4593 case OP_S390_BKCHAIN: {
4594 s390_lgr (code, ins->dreg, ins->sreg1);
4595 if (s390_is_imm16 (cfg->stack_offset)) {
4596 s390_aghi (code, ins->dreg, cfg->stack_offset);
4597 } else if (s390_is_imm32 (cfg->stack_offset)) {
4598 s390_agfi (code, ins->dreg, cfg->stack_offset);
4599 } else {
4600 S390_SET (code, s390_r13, cfg->stack_offset);
4601 s390_agr (code, ins->dreg, s390_r13);
4604 break;
4605 case OP_MEMORY_BARRIER:
4606 s390_mem (code);
4607 break;
4608 case OP_LIVERANGE_START: {
4609 if (cfg->verbose_level > 1)
4610 printf ("R%d START=0x%x\n", MONO_VARINFO (cfg, ins->inst_c0)->vreg, (int)(code - cfg->native_code));
4611 MONO_VARINFO (cfg, ins->inst_c0)->live_range_start = code - cfg->native_code;
4612 break;
4614 case OP_LIVERANGE_END: {
4615 if (cfg->verbose_level > 1)
4616 printf ("R%d END=0x%x\n", MONO_VARINFO (cfg, ins->inst_c0)->vreg, (int)(code - cfg->native_code));
4617 MONO_VARINFO (cfg, ins->inst_c0)->live_range_end = code - cfg->native_code;
4618 break;
4620 case OP_GC_SAFE_POINT: {
4621 short *br;
4623 s390_ltg (code, s390_r0, 0, ins->sreg1, 0);
4624 s390_jz (code, 0); CODEPTR(code, br);
4625 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_JIT_ICALL_ID,
4626 GUINT_TO_POINTER (MONO_JIT_ICALL_mono_threads_state_poll));
4627 S390_CALL_TEMPLATE (code, s390_r14);
4628 PTRSLOT (code, br);
4629 break;
4631 case OP_GC_LIVENESS_DEF:
4632 case OP_GC_LIVENESS_USE:
4633 case OP_GC_PARAM_SLOT_LIVENESS_DEF:
4634 ins->backend.pc_offset = code - cfg->native_code;
4635 break;
4636 case OP_GC_SPILL_SLOT_LIVENESS_DEF:
4637 ins->backend.pc_offset = code - cfg->native_code;
4638 bb->spill_slot_defs = g_slist_prepend_mempool (cfg->mempool, bb->spill_slot_defs, ins);
4639 break;
4640 #ifdef MONO_ARCH_SIMD_INTRINSICS
4641 case OP_ADDPS:
4642 s390x_addps (code, ins->sreg1, ins->sreg2);
4643 break;
4644 case OP_DIVPS:
4645 s390x_divps (code, ins->sreg1, ins->sreg2);
4646 break;
4647 case OP_MULPS:
4648 s390x_mulps (code, ins->sreg1, ins->sreg2);
4649 break;
4650 case OP_SUBPS:
4651 s390x_subps (code, ins->sreg1, ins->sreg2);
4652 break;
4653 case OP_MAXPS:
4654 s390x_maxps (code, ins->sreg1, ins->sreg2);
4655 break;
4656 case OP_MINPS:
4657 s390x_minps (code, ins->sreg1, ins->sreg2);
4658 break;
4659 case OP_COMPPS:
4660 g_assert (ins->inst_c0 >= 0 && ins->inst_c0 <= 7);
4661 s390x_cmpps_imm (code, ins->sreg1, ins->sreg2, ins->inst_c0);
4662 break;
4663 case OP_ANDPS:
4664 s390x_andps (code, ins->sreg1, ins->sreg2);
4665 break;
4666 case OP_ANDNPS:
4667 s390x_andnps (code, ins->sreg1, ins->sreg2);
4668 break;
4669 case OP_ORPS:
4670 s390x_orps (code, ins->sreg1, ins->sreg2);
4671 break;
4672 case OP_XORPS:
4673 s390x_xorps (code, ins->sreg1, ins->sreg2);
4674 break;
4675 case OP_SQRTPS:
4676 s390x_sqrtps (code, ins->dreg, ins->sreg1);
4677 break;
4678 case OP_RSQRTPS:
4679 s390x_rsqrtps (code, ins->dreg, ins->sreg1);
4680 break;
4681 case OP_RCPPS:
4682 s390x_rcpps (code, ins->dreg, ins->sreg1);
4683 break;
4684 case OP_ADDSUBPS:
4685 s390x_addsubps (code, ins->sreg1, ins->sreg2);
4686 break;
4687 case OP_HADDPS:
4688 s390x_haddps (code, ins->sreg1, ins->sreg2);
4689 break;
4690 case OP_HSUBPS:
4691 s390x_hsubps (code, ins->sreg1, ins->sreg2);
4692 break;
4693 case OP_DUPPS_HIGH:
4694 s390x_movshdup (code, ins->dreg, ins->sreg1);
4695 break;
4696 case OP_DUPPS_LOW:
4697 s390x_movsldup (code, ins->dreg, ins->sreg1);
4698 break;
4700 case OP_PSHUFLEW_HIGH:
4701 g_assert (ins->inst_c0 >= 0 && ins->inst_c0 <= 0xFF);
4702 s390x_pshufhw_imm (code, ins->dreg, ins->sreg1, ins->inst_c0);
4703 break;
4704 case OP_PSHUFLEW_LOW:
4705 g_assert (ins->inst_c0 >= 0 && ins->inst_c0 <= 0xFF);
4706 s390x_pshuflw_imm (code, ins->dreg, ins->sreg1, ins->inst_c0);
4707 break;
4708 case OP_PSHUFLED:
4709 g_assert (ins->inst_c0 >= 0 && ins->inst_c0 <= 0xFF);
4710 s390x_pshufd_imm (code, ins->dreg, ins->sreg1, ins->inst_c0);
4711 break;
4712 case OP_SHUFPS:
4713 g_assert (ins->inst_c0 >= 0 && ins->inst_c0 <= 0xFF);
4714 s390x_shufps_imm (code, ins->sreg1, ins->sreg2, ins->inst_c0);
4715 break;
4716 case OP_SHUFPD:
4717 g_assert (ins->inst_c0 >= 0 && ins->inst_c0 <= 0x3);
4718 s390x_shufpd_imm (code, ins->sreg1, ins->sreg2, ins->inst_c0);
4719 break;
4721 case OP_ADDPD:
4722 s390x_addpd (code, ins->sreg1, ins->sreg2);
4723 break;
4724 case OP_DIVPD:
4725 s390x_divpd (code, ins->sreg1, ins->sreg2);
4726 break;
4727 case OP_MULPD:
4728 s390x_mulpd (code, ins->sreg1, ins->sreg2);
4729 break;
4730 case OP_SUBPD:
4731 s390x_subpd (code, ins->sreg1, ins->sreg2);
4732 break;
4733 case OP_MAXPD:
4734 s390x_maxpd (code, ins->sreg1, ins->sreg2);
4735 break;
4736 case OP_MINPD:
4737 s390x_minpd (code, ins->sreg1, ins->sreg2);
4738 break;
4739 case OP_COMPPD:
4740 g_assert (ins->inst_c0 >= 0 && ins->inst_c0 <= 7);
4741 s390x_cmppd_imm (code, ins->sreg1, ins->sreg2, ins->inst_c0);
4742 break;
4743 case OP_ANDPD:
4744 s390x_andpd (code, ins->sreg1, ins->sreg2);
4745 break;
4746 case OP_ANDNPD:
4747 s390x_andnpd (code, ins->sreg1, ins->sreg2);
4748 break;
4749 case OP_ORPD:
4750 s390x_orpd (code, ins->sreg1, ins->sreg2);
4751 break;
4752 case OP_XORPD:
4753 s390x_xorpd (code, ins->sreg1, ins->sreg2);
4754 break;
4755 case OP_SQRTPD:
4756 s390x_sqrtpd (code, ins->dreg, ins->sreg1);
4757 break;
4758 case OP_ADDSUBPD:
4759 s390x_addsubpd (code, ins->sreg1, ins->sreg2);
4760 break;
4761 case OP_HADDPD:
4762 s390x_haddpd (code, ins->sreg1, ins->sreg2);
4763 break;
4764 case OP_HSUBPD:
4765 s390x_hsubpd (code, ins->sreg1, ins->sreg2);
4766 break;
4767 case OP_DUPPD:
4768 s390x_movddup (code, ins->dreg, ins->sreg1);
4769 break;
4771 case OP_EXTRACT_MASK:
4772 s390x_pmovmskb (code, ins->dreg, ins->sreg1);
4773 break;
4775 case OP_PAND:
4776 s390x_pand (code, ins->sreg1, ins->sreg2);
4777 break;
4778 case OP_POR:
4779 s390x_por (code, ins->sreg1, ins->sreg2);
4780 break;
4781 case OP_PXOR:
4782 s390x_pxor (code, ins->sreg1, ins->sreg2);
4783 break;
4785 case OP_PADDB:
4786 s390x_paddb (code, ins->sreg1, ins->sreg2);
4787 break;
4788 case OP_PADDW:
4789 s390x_paddw (code, ins->sreg1, ins->sreg2);
4790 break;
4791 case OP_PADDD:
4792 s390x_paddd (code, ins->sreg1, ins->sreg2);
4793 break;
4794 case OP_PADDQ:
4795 s390x_paddq (code, ins->sreg1, ins->sreg2);
4796 break;
4798 case OP_PSUBB:
4799 s390x_psubb (code, ins->sreg1, ins->sreg2);
4800 break;
4801 case OP_PSUBW:
4802 s390x_psubw (code, ins->sreg1, ins->sreg2);
4803 break;
4804 case OP_PSUBD:
4805 s390x_psubd (code, ins->sreg1, ins->sreg2);
4806 break;
4807 case OP_PSUBQ:
4808 s390x_psubq (code, ins->sreg1, ins->sreg2);
4809 break;
4811 case OP_PMAXB_UN:
4812 s390x_pmaxub (code, ins->sreg1, ins->sreg2);
4813 break;
4814 case OP_PMAXW_UN:
4815 s390x_pmaxuw (code, ins->sreg1, ins->sreg2);
4816 break;
4817 case OP_PMAXD_UN:
4818 s390x_pmaxud (code, ins->sreg1, ins->sreg2);
4819 break;
4821 case OP_PMAXB:
4822 s390x_pmaxsb (code, ins->sreg1, ins->sreg2);
4823 break;
4824 case OP_PMAXW:
4825 s390x_pmaxsw (code, ins->sreg1, ins->sreg2);
4826 break;
4827 case OP_PMAXD:
4828 s390x_pmaxsd (code, ins->sreg1, ins->sreg2);
4829 break;
4831 case OP_PAVGB_UN:
4832 s390x_pavgb (code, ins->sreg1, ins->sreg2);
4833 break;
4834 case OP_PAVGW_UN:
4835 s390x_pavgw (code, ins->sreg1, ins->sreg2);
4836 break;
4838 case OP_PMINB_UN:
4839 s390x_pminub (code, ins->sreg1, ins->sreg2);
4840 break;
4841 case OP_PMINW_UN:
4842 s390x_pminuw (code, ins->sreg1, ins->sreg2);
4843 break;
4844 case OP_PMIND_UN:
4845 s390x_pminud (code, ins->sreg1, ins->sreg2);
4846 break;
4848 case OP_PMINB:
4849 s390x_pminsb (code, ins->sreg1, ins->sreg2);
4850 break;
4851 case OP_PMINW:
4852 s390x_pminsw (code, ins->sreg1, ins->sreg2);
4853 break;
4854 case OP_PMIND:
4855 s390x_pminsd (code, ins->sreg1, ins->sreg2);
4856 break;
4858 case OP_PCMPEQB:
4859 s390x_pcmpeqb (code, ins->sreg1, ins->sreg2);
4860 break;
4861 case OP_PCMPEQW:
4862 s390x_pcmpeqw (code, ins->sreg1, ins->sreg2);
4863 break;
4864 case OP_PCMPEQD:
4865 s390x_pcmpeqd (code, ins->sreg1, ins->sreg2);
4866 break;
4867 case OP_PCMPEQQ:
4868 s390x_pcmpeqq (code, ins->sreg1, ins->sreg2);
4869 break;
4871 case OP_PCMPGTB:
4872 s390x_pcmpgtb (code, ins->sreg1, ins->sreg2);
4873 break;
4874 case OP_PCMPGTW:
4875 s390x_pcmpgtw (code, ins->sreg1, ins->sreg2);
4876 break;
4877 case OP_PCMPGTD:
4878 s390x_pcmpgtd (code, ins->sreg1, ins->sreg2);
4879 break;
4880 case OP_PCMPGTQ:
4881 s390x_pcmpgtq (code, ins->sreg1, ins->sreg2);
4882 break;
4884 case OP_PSUM_ABS_DIFF:
4885 s390x_psadbw (code, ins->sreg1, ins->sreg2);
4886 break;
4888 case OP_UNPACK_LOWB:
4889 s390x_punpcklbw (code, ins->sreg1, ins->sreg2);
4890 break;
4891 case OP_UNPACK_LOWW:
4892 s390x_punpcklwd (code, ins->sreg1, ins->sreg2);
4893 break;
4894 case OP_UNPACK_LOWD:
4895 s390x_punpckldq (code, ins->sreg1, ins->sreg2);
4896 break;
4897 case OP_UNPACK_LOWQ:
4898 s390x_punpcklqdq (code, ins->sreg1, ins->sreg2);
4899 break;
4900 case OP_UNPACK_LOWPS:
4901 s390x_unpcklps (code, ins->sreg1, ins->sreg2);
4902 break;
4903 case OP_UNPACK_LOWPD:
4904 s390x_unpcklpd (code, ins->sreg1, ins->sreg2);
4905 break;
4907 case OP_UNPACK_HIGHB:
4908 s390x_punpckhbw (code, ins->sreg1, ins->sreg2);
4909 break;
4910 case OP_UNPACK_HIGHW:
4911 s390x_punpckhwd (code, ins->sreg1, ins->sreg2);
4912 break;
4913 case OP_UNPACK_HIGHD:
4914 s390x_punpckhdq (code, ins->sreg1, ins->sreg2);
4915 break;
4916 case OP_UNPACK_HIGHQ:
4917 s390x_punpckhqdq (code, ins->sreg1, ins->sreg2);
4918 break;
4919 case OP_UNPACK_HIGHPS:
4920 s390x_unpckhps (code, ins->sreg1, ins->sreg2);
4921 break;
4922 case OP_UNPACK_HIGHPD:
4923 s390x_unpckhpd (code, ins->sreg1, ins->sreg2);
4924 break;
4926 case OP_PACKW:
4927 s390x_packsswb (code, ins->sreg1, ins->sreg2);
4928 break;
4929 case OP_PACKD:
4930 s390x_packssdw (code, ins->sreg1, ins->sreg2);
4931 break;
4932 case OP_PACKW_UN:
4933 s390x_packuswb (code, ins->sreg1, ins->sreg2);
4934 break;
4935 case OP_PACKD_UN:
4936 s390x_packusdw (code, ins->sreg1, ins->sreg2);
4937 break;
4939 case OP_PADDB_SAT_UN:
4940 s390x_paddusb (code, ins->sreg1, ins->sreg2);
4941 break;
4942 case OP_PSUBB_SAT_UN:
4943 s390x_psubusb (code, ins->sreg1, ins->sreg2);
4944 break;
4945 case OP_PADDW_SAT_UN:
4946 s390x_paddusw (code, ins->sreg1, ins->sreg2);
4947 break;
4948 case OP_PSUBW_SAT_UN:
4949 s390x_psubusw (code, ins->sreg1, ins->sreg2);
4950 break;
4952 case OP_PADDB_SAT:
4953 s390x_paddsb (code, ins->sreg1, ins->sreg2);
4954 break;
4955 case OP_PSUBB_SAT:
4956 s390x_psubsb (code, ins->sreg1, ins->sreg2);
4957 break;
4958 case OP_PADDW_SAT:
4959 s390x_paddsw (code, ins->sreg1, ins->sreg2);
4960 break;
4961 case OP_PSUBW_SAT:
4962 s390x_psubsw (code, ins->sreg1, ins->sreg2);
4963 break;
4965 case OP_PMULW:
4966 s390x_pmullw (code, ins->sreg1, ins->sreg2);
4967 break;
4968 case OP_PMULD:
4969 s390x_pmulld (code, ins->sreg1, ins->sreg2);
4970 break;
4971 case OP_PMULQ:
4972 s390x_pmuludq (code, ins->sreg1, ins->sreg2);
4973 break;
4974 case OP_PMULW_HIGH_UN:
4975 s390x_pmulhuw (code, ins->sreg1, ins->sreg2);
4976 break;
4977 case OP_PMULW_HIGH:
4978 s390x_pmulhw (code, ins->sreg1, ins->sreg2);
4979 break;
4981 case OP_PSHRW:
4982 s390x_psrlw_reg_imm (code, ins->dreg, ins->inst_imm);
4983 break;
4984 case OP_PSHRW_REG:
4985 s390x_psrlw (code, ins->dreg, ins->sreg2);
4986 break;
4988 case OP_PSARW:
4989 s390x_psraw_reg_imm (code, ins->dreg, ins->inst_imm);
4990 break;
4991 case OP_PSARW_REG:
4992 s390x_psraw (code, ins->dreg, ins->sreg2);
4993 break;
4995 case OP_PSHLW:
4996 s390x_psllw_reg_imm (code, ins->dreg, ins->inst_imm);
4997 break;
4998 case OP_PSHLW_REG:
4999 s390x_psllw (code, ins->dreg, ins->sreg2);
5000 break;
5002 case OP_PSHRD:
5003 s390x_psrld_reg_imm (code, ins->dreg, ins->inst_imm);
5004 break;
5005 case OP_PSHRD_REG:
5006 s390x_psrld (code, ins->dreg, ins->sreg2);
5007 break;
5009 case OP_PSARD:
5010 s390x_psrad_reg_imm (code, ins->dreg, ins->inst_imm);
5011 break;
5012 case OP_PSARD_REG:
5013 s390x_psrad (code, ins->dreg, ins->sreg2);
5014 break;
5016 case OP_PSHLD:
5017 s390x_pslld_reg_imm (code, ins->dreg, ins->inst_imm);
5018 break;
5019 case OP_PSHLD_REG:
5020 s390x_pslld (code, ins->dreg, ins->sreg2);
5021 break;
5023 case OP_PSHRQ:
5024 s390x_psrlq_reg_imm (code, ins->dreg, ins->inst_imm);
5025 break;
5026 case OP_PSHRQ_REG:
5027 s390x_psrlq (code, ins->dreg, ins->sreg2);
5028 break;
5030 /*TODO: This is appart of the sse spec but not added
5031 case OP_PSARQ:
5032 s390x_psraq_reg_imm (code, ins->dreg, ins->inst_imm);
5033 break;
5034 case OP_PSARQ_REG:
5035 s390x_psraq (code, ins->dreg, ins->sreg2);
5036 break;
5039 case OP_PSHLQ:
5040 s390x_psllq_reg_imm (code, ins->dreg, ins->inst_imm);
5041 break;
5042 case OP_PSHLQ_REG:
5043 s390x_psllq (code, ins->dreg, ins->sreg2);
5044 break;
5045 case OP_CVTDQ2PD:
5046 s390x_cvtdq2pd (code, ins->dreg, ins->sreg1);
5047 break;
5048 case OP_CVTDQ2PS:
5049 s390x_cvtdq2ps (code, ins->dreg, ins->sreg1);
5050 break;
5051 case OP_CVTPD2DQ:
5052 s390x_cvtpd2dq (code, ins->dreg, ins->sreg1);
5053 break;
5054 case OP_CVTPD2PS:
5055 s390x_cvtpd2ps (code, ins->dreg, ins->sreg1);
5056 break;
5057 case OP_CVTPS2DQ:
5058 s390x_cvtps2dq (code, ins->dreg, ins->sreg1);
5059 break;
5060 case OP_CVTPS2PD:
5061 s390x_cvtps2pd (code, ins->dreg, ins->sreg1);
5062 break;
5063 case OP_CVTTPD2DQ:
5064 s390x_cvttpd2dq (code, ins->dreg, ins->sreg1);
5065 break;
5066 case OP_CVTTPS2DQ:
5067 s390x_cvttps2dq (code, ins->dreg, ins->sreg1);
5068 break;
5070 case OP_ICONV_TO_X:
5071 amd64_movd_xreg_reg_size (code, ins->dreg, ins->sreg1, 4);
5072 break;
5073 case OP_EXTRACT_I4:
5074 amd64_movd_reg_xreg_size (code, ins->dreg, ins->sreg1, 4);
5075 break;
5076 case OP_EXTRACT_I8:
5077 if (ins->inst_c0) {
5078 amd64_movhlps (code, MONO_ARCH_FP_SCRATCH_REG, ins->sreg1);
5079 amd64_movd_reg_xreg_size (code, ins->dreg, MONO_ARCH_FP_SCRATCH_REG, 8);
5080 } else {
5081 amd64_movd_reg_xreg_size (code, ins->dreg, ins->sreg1, 8);
5083 break;
5084 case OP_EXTRACT_I1:
5085 case OP_EXTRACT_U1:
5086 amd64_movd_reg_xreg_size (code, ins->dreg, ins->sreg1, 4);
5087 if (ins->inst_c0)
5088 amd64_shift_reg_imm (code, X86_SHR, ins->dreg, ins->inst_c0 * 8);
5089 amd64_widen_reg (code, ins->dreg, ins->dreg, ins->opcode == OP_EXTRACT_I1, FALSE);
5090 break;
5091 case OP_EXTRACT_I2:
5092 case OP_EXTRACT_U2:
5093 /*amd64_movd_reg_xreg_size (code, ins->dreg, ins->sreg1, 4);
5094 if (ins->inst_c0)
5095 amd64_shift_reg_imm_size (code, X86_SHR, ins->dreg, 16, 4);*/
5096 s390x_pextrw_imm (code, ins->dreg, ins->sreg1, ins->inst_c0);
5097 amd64_widen_reg_size (code, ins->dreg, ins->dreg, ins->opcode == OP_EXTRACT_I2, TRUE, 4);
5098 break;
5099 case OP_EXTRACT_R8:
5100 if (ins->inst_c0)
5101 amd64_movhlps (code, ins->dreg, ins->sreg1);
5102 else
5103 s390x_movsd (code, ins->dreg, ins->sreg1);
5104 break;
5105 case OP_INSERT_I2:
5106 s390x_pinsrw_imm (code, ins->sreg1, ins->sreg2, ins->inst_c0);
5107 break;
5108 case OP_EXTRACTX_U2:
5109 s390x_pextrw_imm (code, ins->dreg, ins->sreg1, ins->inst_c0);
5110 break;
5111 case OP_INSERTX_U1_SLOW:
5112 /*sreg1 is the extracted ireg (scratch)
5113 /sreg2 is the to be inserted ireg (scratch)
5114 /dreg is the xreg to receive the value*/
5116 /*clear the bits from the extracted word*/
5117 amd64_alu_reg_imm (code, X86_AND, ins->sreg1, ins->inst_c0 & 1 ? 0x00FF : 0xFF00);
5118 /*shift the value to insert if needed*/
5119 if (ins->inst_c0 & 1)
5120 amd64_shift_reg_imm_size (code, X86_SHL, ins->sreg2, 8, 4);
5121 /*join them together*/
5122 amd64_alu (code, X86_OR, ins->sreg1, ins->sreg2);
5123 s390x_pinsrw_imm (code, ins->dreg, ins->sreg1, ins->inst_c0 / 2);
5124 break;
5125 case OP_INSERTX_I4_SLOW:
5126 s390x_pinsrw_imm (code, ins->dreg, ins->sreg2, ins->inst_c0 * 2);
5127 amd64_shift_reg_imm (code, X86_SHR, ins->sreg2, 16);
5128 s390x_pinsrw_imm (code, ins->dreg, ins->sreg2, ins->inst_c0 * 2 + 1);
5129 break;
5130 case OP_INSERTX_I8_SLOW:
5131 amd64_movd_xreg_reg_size(code, MONO_ARCH_FP_SCRATCH_REG, ins->sreg2, 8);
5132 if (ins->inst_c0)
5133 amd64_movlhps (code, ins->dreg, MONO_ARCH_FP_SCRATCH_REG);
5134 else
5135 s390x_movsd (code, ins->dreg, MONO_ARCH_FP_SCRATCH_REG);
5136 break;
5138 case OP_INSERTX_R4_SLOW:
5139 switch (ins->inst_c0) {
5140 case 0:
5141 if (cfg->r4fp)
5142 s390x_movss (code, ins->dreg, ins->sreg2);
5143 else
5144 s390x_cvtsd2ss (code, ins->dreg, ins->sreg2);
5145 break;
5146 case 1:
5147 s390x_pshufd_imm (code, ins->dreg, ins->dreg, mono_simd_shuffle_mask(1, 0, 2, 3));
5148 if (cfg->r4fp)
5149 s390x_movss (code, ins->dreg, ins->sreg2);
5150 else
5151 s390x_cvtsd2ss (code, ins->dreg, ins->sreg2);
5152 s390x_pshufd_imm (code, ins->dreg, ins->dreg, mono_simd_shuffle_mask(1, 0, 2, 3));
5153 break;
5154 case 2:
5155 s390x_pshufd_imm (code, ins->dreg, ins->dreg, mono_simd_shuffle_mask(2, 1, 0, 3));
5156 if (cfg->r4fp)
5157 s390x_movss (code, ins->dreg, ins->sreg2);
5158 else
5159 s390x_cvtsd2ss (code, ins->dreg, ins->sreg2);
5160 s390x_pshufd_imm (code, ins->dreg, ins->dreg, mono_simd_shuffle_mask(2, 1, 0, 3));
5161 break;
5162 case 3:
5163 s390x_pshufd_imm (code, ins->dreg, ins->dreg, mono_simd_shuffle_mask(3, 1, 2, 0));
5164 if (cfg->r4fp)
5165 s390x_movss (code, ins->dreg, ins->sreg2);
5166 else
5167 s390x_cvtsd2ss (code, ins->dreg, ins->sreg2);
5168 s390x_pshufd_imm (code, ins->dreg, ins->dreg, mono_simd_shuffle_mask(3, 1, 2, 0));
5169 break;
5171 break;
5172 case OP_INSERTX_R8_SLOW:
5173 if (ins->inst_c0)
5174 amd64_movlhps (code, ins->dreg, ins->sreg2);
5175 else
5176 s390x_movsd (code, ins->dreg, ins->sreg2);
5177 break;
5178 case OP_STOREX_MEMBASE_REG:
5179 case OP_STOREX_MEMBASE:
5180 s390x_movups_membase_reg (code, ins->dreg, ins->inst_offset, ins->sreg1);
5181 break;
5182 case OP_LOADX_MEMBASE:
5183 s390x_movups_reg_membase (code, ins->dreg, ins->sreg1, ins->inst_offset);
5184 break;
5185 case OP_LOADX_ALIGNED_MEMBASE:
5186 s390x_movaps_reg_membase (code, ins->dreg, ins->sreg1, ins->inst_offset);
5187 break;
5188 case OP_STOREX_ALIGNED_MEMBASE_REG:
5189 s390x_movaps_membase_reg (code, ins->dreg, ins->inst_offset, ins->sreg1);
5190 break;
5191 case OP_STOREX_NTA_MEMBASE_REG:
5192 s390x_movntps_reg_membase (code, ins->dreg, ins->sreg1, ins->inst_offset);
5193 break;
5194 case OP_PREFETCH_MEMBASE:
5195 s390x_prefetch_reg_membase (code, ins->backend.arg_info, ins->sreg1, ins->inst_offset);
5196 break;
5198 case OP_XMOVE:
5199 /*FIXME the peephole pass should have killed this*/
5200 if (ins->dreg != ins->sreg1)
5201 s390x_movaps (code, ins->dreg, ins->sreg1);
5202 break;
5203 case OP_XZERO:
5204 s390x_pxor (code, ins->dreg, ins->dreg);
5205 break;
5206 case OP_ICONV_TO_R4_RAW:
5207 amd64_movd_xreg_reg_size (code, ins->dreg, ins->sreg1, 4);
5208 break;
5210 case OP_FCONV_TO_R8_X:
5211 s390x_movsd (code, ins->dreg, ins->sreg1);
5212 break;
5214 case OP_XCONV_R8_TO_I4:
5215 s390x_cvttsd2si_reg_xreg_size (code, ins->dreg, ins->sreg1, 4);
5216 switch (ins->backend.source_opcode) {
5217 case OP_FCONV_TO_I1:
5218 amd64_widen_reg (code, ins->dreg, ins->dreg, TRUE, FALSE);
5219 break;
5220 case OP_FCONV_TO_U1:
5221 amd64_widen_reg (code, ins->dreg, ins->dreg, FALSE, FALSE);
5222 break;
5223 case OP_FCONV_TO_I2:
5224 amd64_widen_reg (code, ins->dreg, ins->dreg, TRUE, TRUE);
5225 break;
5226 case OP_FCONV_TO_U2:
5227 amd64_widen_reg (code, ins->dreg, ins->dreg, FALSE, TRUE);
5228 break;
5230 break;
5232 case OP_EXPAND_I2:
5233 s390x_pinsrw_imm (code, ins->dreg, ins->sreg1, 0);
5234 s390x_pinsrw_imm (code, ins->dreg, ins->sreg1, 1);
5235 s390x_pshufd_imm (code, ins->dreg, ins->dreg, 0);
5236 break;
5237 case OP_EXPAND_I4:
5238 amd64_movd_xreg_reg_size (code, ins->dreg, ins->sreg1, 4);
5239 s390x_pshufd_imm (code, ins->dreg, ins->dreg, 0);
5240 break;
5241 case OP_EXPAND_I8:
5242 amd64_movd_xreg_reg_size (code, ins->dreg, ins->sreg1, 8);
5243 s390x_pshufd_imm (code, ins->dreg, ins->dreg, 0x44);
5244 break;
5245 case OP_EXPAND_R4:
5246 if (cfg->r4fp) {
5247 s390x_movsd (code, ins->dreg, ins->sreg1);
5248 } else {
5249 s390x_movsd (code, ins->dreg, ins->sreg1);
5250 s390x_cvtsd2ss (code, ins->dreg, ins->dreg);
5252 s390x_pshufd_imm (code, ins->dreg, ins->dreg, 0);
5253 break;
5254 case OP_EXPAND_R8:
5255 s390x_movsd (code, ins->dreg, ins->sreg1);
5256 s390x_pshufd_imm (code, ins->dreg, ins->dreg, 0x44);
5257 break;
5258 #endif
5259 default:
5260 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
5261 g_assert_not_reached ();
5264 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
5265 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
5266 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
5267 g_assert_not_reached ();
5271 set_code_cursor (cfg, code);
5274 /*========================= End of Function ========================*/
5276 /*------------------------------------------------------------------*/
5277 /* */
5278 /* Name - mono_arch_register_lowlevel_calls */
5279 /* */
5280 /* Function - Register routines to help with --trace operation. */
5281 /* */
5282 /*------------------------------------------------------------------*/
5284 void
5285 mono_arch_register_lowlevel_calls (void)
5289 /*========================= End of Function ========================*/
5291 /*------------------------------------------------------------------*/
5292 /* */
5293 /* Name - mono_arch_patch_code */
5294 /* */
5295 /* Function - Process the patch data created during the */
5296 /* instruction build process. This resolves jumps, */
5297 /* calls, variables etc. */
5298 /* */
5299 /*------------------------------------------------------------------*/
5301 void
5302 mono_arch_patch_code (MonoCompile *cfg, MonoMethod *method, MonoDomain *domain,
5303 guint8 *code, MonoJumpInfo *ji, gboolean run_cctors,
5304 MonoError *error)
5306 MonoJumpInfo *patch_info;
5308 error_init (error);
5310 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
5311 unsigned char *ip = patch_info->ip.i + code;
5312 gconstpointer target = NULL;
5314 target = mono_resolve_patch_target (method, domain, code,
5315 patch_info, run_cctors, error);
5316 return_if_nok (error);
5318 switch (patch_info->type) {
5319 case MONO_PATCH_INFO_IP:
5320 case MONO_PATCH_INFO_LDSTR:
5321 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
5322 case MONO_PATCH_INFO_LDTOKEN:
5323 case MONO_PATCH_INFO_EXC:
5324 s390_patch_addr (ip, (guint64) target);
5325 continue;
5326 case MONO_PATCH_INFO_SPECIFIC_TRAMPOLINE_LAZY_FETCH_ADDR:
5327 case MONO_PATCH_INFO_METHOD:
5328 case MONO_PATCH_INFO_JIT_ICALL_ID:
5329 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
5330 case MONO_PATCH_INFO_RGCTX_FETCH:
5331 case MONO_PATCH_INFO_ABS: {
5332 S390_EMIT_CALL (ip, target);
5333 continue;
5335 case MONO_PATCH_INFO_SWITCH:
5336 /*----------------------------------*/
5337 /* ip points at the basr r13,0/j +4 */
5338 /* instruction the vtable value */
5339 /* follows this (i.e. ip+6) */
5340 /*----------------------------------*/
5341 S390_EMIT_LOAD (ip, target);
5342 continue;
5343 case MONO_PATCH_INFO_METHODCONST:
5344 case MONO_PATCH_INFO_CLASS:
5345 case MONO_PATCH_INFO_IMAGE:
5346 case MONO_PATCH_INFO_FIELD:
5347 case MONO_PATCH_INFO_IID:
5348 case MONO_PATCH_INFO_EXC_NAME:
5349 target = S390_RELATIVE(target, ip);
5350 s390_patch_rel (ip, (guint64) target);
5351 continue;
5352 case MONO_PATCH_INFO_R4:
5353 case MONO_PATCH_INFO_R8:
5354 g_assert_not_reached ();
5355 continue;
5356 default:
5357 target = S390_RELATIVE(target, ip);
5358 ip += 2;
5359 s390_patch_rel (ip, (guint64) target);
5360 case MONO_PATCH_INFO_NONE:
5361 break;
5366 /*========================= End of Function ========================*/
5368 /*------------------------------------------------------------------*/
5369 /* */
5370 /* Name - mono_arch_emit_prolog */
5371 /* */
5372 /* Function - Create the instruction sequence for a function */
5373 /* prolog. */
5374 /* */
5375 /*------------------------------------------------------------------*/
5377 guint8 *
5378 mono_arch_emit_prolog (MonoCompile *cfg)
5380 MonoMethod *method = cfg->method;
5381 MonoBasicBlock *bb;
5382 MonoMethodSignature *sig;
5383 MonoInst *inst;
5384 long alloc_size, pos, max_offset, i, cfa_offset = 0;
5385 guint8 *code;
5386 guint32 size;
5387 CallInfo *cinfo;
5388 int argsClobbered = 0,
5389 lmfOffset,
5390 fpOffset = 0;
5392 cfg->code_size = 512;
5394 if (method->save_lmf)
5395 cfg->code_size += 200;
5397 cfg->native_code = code = g_malloc (cfg->code_size);
5399 mono_emit_unwind_op_def_cfa (cfg, code, STK_BASE, 0);
5400 emit_unwind_regs(cfg, code, s390_r6, s390_r14, S390_REG_SAVE_OFFSET);
5401 s390_stmg (code, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
5402 mono_emit_unwind_op_offset (cfg, code, s390_r14, S390_RET_ADDR_OFFSET);
5403 mini_gc_set_slot_type_from_cfa (cfg, S390_RET_ADDR_OFFSET, SLOT_NOREF);
5404 if (cfg->arch.bkchain_reg != -1)
5405 s390_lgr (code, cfg->arch.bkchain_reg, STK_BASE);
5407 if (cfg->flags & MONO_CFG_HAS_ALLOCA) {
5408 cfg->used_int_regs |= 1 << s390_r11;
5411 if ((cfg->arch.used_fp_regs & S390_FP_SAVE_MASK) != 0) {
5412 for (int i=8; i<16; i++) {
5413 if (cfg->arch.used_fp_regs & (1 << i))
5414 fpOffset += sizeof(double);
5416 fpOffset = S390_ALIGN(fpOffset, 16);
5418 cfg->arch.fpSize = fpOffset;
5420 alloc_size = cfg->stack_offset + fpOffset;
5422 cfg->stack_usage = cfa_offset = alloc_size;
5423 s390_lgr (code, s390_r11, STK_BASE);
5424 if (s390_is_imm16 (alloc_size)) {
5425 s390_aghi (code, STK_BASE, -alloc_size);
5426 } else if (s390_is_imm32 (alloc_size)) {
5427 s390_agfi (code, STK_BASE, -alloc_size);
5428 } else {
5429 int stackSize = alloc_size;
5430 while (stackSize > INT_MAX) {
5431 s390_agfi (code, STK_BASE, -INT_MAX);
5432 stackSize -= INT_MAX;
5434 s390_agfi (code, STK_BASE, -stackSize);
5436 s390_stg (code, s390_r11, 0, STK_BASE, 0);
5438 if (fpOffset > 0) {
5439 int stkOffset = 0;
5441 s390_lgr (code, s390_r1, s390_r11);
5442 s390_aghi (code, s390_r1, -fpOffset);
5443 for (int i=8; i<16; i++) {
5444 if (cfg->arch.used_fp_regs & (1 << i)) {
5445 emit_unwind_regs(cfg, code, 16+i, 16+i, stkOffset+fpOffset);
5446 s390_std (code, i, 0, s390_r1, stkOffset);
5447 stkOffset += sizeof(double);
5452 mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
5454 if (cfg->frame_reg != STK_BASE)
5455 s390_lgr (code, s390_r11, STK_BASE);
5457 mono_emit_unwind_op_def_cfa_reg (cfg, code, cfg->frame_reg);
5459 /* store runtime generic context */
5460 if (cfg->rgctx_var) {
5461 g_assert (cfg->rgctx_var->opcode == OP_REGOFFSET);
5463 s390_stg (code, MONO_ARCH_RGCTX_REG, 0,
5464 cfg->rgctx_var->inst_basereg,
5465 cfg->rgctx_var->inst_offset);
5468 /* compute max_offset in order to use short forward jumps
5469 * we always do it on s390 because the immediate displacement
5470 * for jumps is too small
5472 max_offset = 0;
5473 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
5474 MonoInst *ins;
5475 bb->max_offset = max_offset;
5477 MONO_BB_FOR_EACH_INS (bb, ins)
5478 max_offset += ins_get_size (ins->opcode);
5481 /* load arguments allocated to register from the stack */
5482 sig = mono_method_signature_internal (method);
5483 pos = 0;
5485 cinfo = get_call_info (cfg->mempool, sig);
5487 if (cinfo->struct_ret) {
5488 ArgInfo *ainfo = &cinfo->ret;
5489 inst = cfg->vret_addr;
5490 inst->backend.size = ainfo->vtsize;
5491 s390_stg (code, ainfo->reg, 0, inst->inst_basereg, inst->inst_offset);
5494 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
5495 ArgInfo *ainfo = cinfo->args + i;
5496 inst = cfg->args [pos];
5498 if (inst->opcode == OP_VTARG_ADDR)
5499 inst = inst->inst_left;
5501 if (inst->opcode == OP_REGVAR) {
5502 if (ainfo->regtype == RegTypeGeneral)
5503 s390_lgr (code, inst->dreg, ainfo->reg);
5504 else if (ainfo->regtype == RegTypeFP) {
5505 if (inst->dreg != ainfo->reg) {
5506 s390_ldr (code, inst->dreg, ainfo->reg);
5508 } else if (ainfo->regtype == RegTypeFPR4) {
5509 if (!cfg->r4fp)
5510 s390_ledbr (code, inst->dreg, ainfo->reg);
5511 } else if (ainfo->regtype == RegTypeBase) {
5512 s390_lgr (code, s390_r13, STK_BASE);
5513 s390_aghi (code, s390_r13, alloc_size);
5514 s390_lg (code, inst->dreg, 0, s390_r13, ainfo->offset);
5515 } else
5516 g_assert_not_reached ();
5518 if (cfg->verbose_level > 2)
5519 g_print ("Argument %d assigned to register %s\n",
5520 pos, mono_arch_regname (inst->dreg));
5521 } else {
5522 if (ainfo->regtype == RegTypeGeneral) {
5523 if (!((ainfo->reg >= 2) && (ainfo->reg <= 6)))
5524 g_assert_not_reached();
5525 switch (ainfo->size) {
5526 case 1:
5527 s390_stc (code, ainfo->reg, 0, inst->inst_basereg, inst->inst_offset);
5528 break;
5529 case 2:
5530 s390_sth (code, ainfo->reg, 0, inst->inst_basereg, inst->inst_offset);
5531 break;
5532 case 4:
5533 s390_st (code, ainfo->reg, 0, inst->inst_basereg, inst->inst_offset);
5534 break;
5535 case 8:
5536 s390_stg (code, ainfo->reg, 0, inst->inst_basereg, inst->inst_offset);
5537 break;
5539 } else if (ainfo->regtype == RegTypeBase) {
5540 } else if (ainfo->regtype == RegTypeFP) {
5541 s390_std (code, ainfo->reg, 0, inst->inst_basereg, inst->inst_offset);
5542 } else if (ainfo->regtype == RegTypeFPR4) {
5543 s390_ste (code, ainfo->reg, 0, inst->inst_basereg, inst->inst_offset);
5544 } else if (ainfo->regtype == RegTypeStructByVal) {
5545 int doffset = inst->inst_offset;
5546 int reg;
5547 if (ainfo->reg != STK_BASE)
5548 reg = ainfo->reg;
5549 else {
5550 reg = s390_r0;
5551 s390_lgr (code, s390_r13, STK_BASE);
5552 s390_aghi (code, s390_r13, alloc_size);
5555 size = (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE
5556 ? mono_class_native_size(mono_class_from_mono_type_internal (inst->inst_vtype), NULL)
5557 : ainfo->size);
5559 switch (size) {
5560 case 1:
5561 if (ainfo->reg == STK_BASE)
5562 s390_ic (code, reg, 0, s390_r13, ainfo->offset+7);
5563 s390_stc (code, reg, 0, inst->inst_basereg, doffset);
5564 break;
5565 case 2:
5566 if (ainfo->reg == STK_BASE)
5567 s390_lh (code, reg, 0, s390_r13, ainfo->offset+6);
5568 s390_sth (code, reg, 0, inst->inst_basereg, doffset);
5569 break;
5570 case 4:
5571 if (ainfo->reg == STK_BASE)
5572 s390_l (code, reg, 0, s390_r13, ainfo->offset+4);
5573 s390_st (code, reg, 0, inst->inst_basereg, doffset);
5574 break;
5575 case 8:
5576 if (ainfo->reg == STK_BASE)
5577 s390_lg (code, reg, 0, s390_r13, ainfo->offset);
5578 s390_stg (code, reg, 0, inst->inst_basereg, doffset);
5579 break;
5581 } else if (ainfo->regtype == RegTypeStructByAddr) {
5582 s390_stg (code, ainfo->reg, 0, inst->inst_basereg, inst->inst_offset);
5583 } else if (ainfo->regtype == RegTypeStructByAddrOnStack) {
5584 } else
5585 g_assert_not_reached ();
5587 pos++;
5590 if (method->save_lmf) {
5591 /*---------------------------------------------------------------*/
5592 /* build the MonoLMF structure on the stack - see mini-s390x.h */
5593 /*---------------------------------------------------------------*/
5594 lmfOffset = alloc_size - sizeof(MonoLMF);
5596 s390_lgr (code, s390_r13, cfg->frame_reg);
5597 s390_aghi (code, s390_r13, lmfOffset);
5599 /*---------------------------------------------------------------*/
5600 /* Preserve the parameter registers while we fix up the lmf */
5601 /*---------------------------------------------------------------*/
5602 s390_stmg (code, s390_r2, s390_r6, s390_r13,
5603 G_STRUCT_OFFSET(MonoLMF, pregs[0]));
5605 mini_gc_set_slot_type_from_fp (cfg, lmfOffset + MONO_STRUCT_OFFSET (MonoLMF, pregs[0]), SLOT_NOREF);
5606 mini_gc_set_slot_type_from_fp (cfg, lmfOffset + MONO_STRUCT_OFFSET (MonoLMF, pregs[1]), SLOT_NOREF);
5607 mini_gc_set_slot_type_from_fp (cfg, lmfOffset + MONO_STRUCT_OFFSET (MonoLMF, pregs[2]), SLOT_NOREF);
5608 mini_gc_set_slot_type_from_fp (cfg, lmfOffset + MONO_STRUCT_OFFSET (MonoLMF, pregs[3]), SLOT_NOREF);
5609 mini_gc_set_slot_type_from_fp (cfg, lmfOffset + MONO_STRUCT_OFFSET (MonoLMF, pregs[4]), SLOT_NOREF);
5611 /*---------------------------------------------------------------*/
5612 /* On return from this call r2 have the address of the &lmf */
5613 /*---------------------------------------------------------------*/
5614 mono_add_patch_info (cfg, code - cfg->native_code,
5615 MONO_PATCH_INFO_JIT_ICALL_ID,
5616 GUINT_TO_POINTER (MONO_JIT_ICALL_mono_tls_get_lmf_addr));
5617 S390_CALL_TEMPLATE(code, s390_r1);
5619 /*---------------------------------------------------------------*/
5620 /* Set lmf.lmf_addr = jit_tls->lmf */
5621 /*---------------------------------------------------------------*/
5622 s390_stg (code, s390_r2, 0, s390_r13,
5623 G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5624 mini_gc_set_slot_type_from_fp (cfg, lmfOffset + MONO_STRUCT_OFFSET (MonoLMF, lmf_addr), SLOT_NOREF);
5626 /*---------------------------------------------------------------*/
5627 /* Get current lmf */
5628 /*---------------------------------------------------------------*/
5629 s390_lg (code, s390_r0, 0, s390_r2, 0);
5631 /*---------------------------------------------------------------*/
5632 /* Set our lmf as the current lmf */
5633 /*---------------------------------------------------------------*/
5634 s390_stg (code, s390_r13, 0, s390_r2, 0);
5636 /*---------------------------------------------------------------*/
5637 /* Have our lmf.previous_lmf point to the last lmf */
5638 /*---------------------------------------------------------------*/
5639 s390_stg (code, s390_r0, 0, s390_r13,
5640 G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5641 mini_gc_set_slot_type_from_fp (cfg, lmfOffset + MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), SLOT_NOREF);
5643 /*---------------------------------------------------------------*/
5644 /* save method info */
5645 /*---------------------------------------------------------------*/
5646 S390_SET (code, s390_r1, method);
5647 s390_stg (code, s390_r1, 0, s390_r13,
5648 G_STRUCT_OFFSET(MonoLMF, method));
5649 mini_gc_set_slot_type_from_fp (cfg, lmfOffset + MONO_STRUCT_OFFSET (MonoLMF, method), SLOT_NOREF);
5651 /*---------------------------------------------------------------*/
5652 /* save the current IP */
5653 /*---------------------------------------------------------------*/
5654 s390_stg (code, STK_BASE, 0, s390_r13, G_STRUCT_OFFSET(MonoLMF, ebp));
5655 s390_basr (code, s390_r1, 0);
5656 s390_stg (code, s390_r1, 0, s390_r13, G_STRUCT_OFFSET(MonoLMF, eip));
5657 mini_gc_set_slot_type_from_fp (cfg, lmfOffset + MONO_STRUCT_OFFSET (MonoLMF, ebp), SLOT_NOREF);
5658 mini_gc_set_slot_type_from_fp (cfg, lmfOffset + MONO_STRUCT_OFFSET (MonoLMF, eip), SLOT_NOREF);
5660 /*---------------------------------------------------------------*/
5661 /* Save general and floating point registers */
5662 /*---------------------------------------------------------------*/
5663 s390_stmg (code, s390_r2, s390_r12, s390_r13,
5664 G_STRUCT_OFFSET(MonoLMF, gregs[2]));
5665 mini_gc_set_slot_type_from_fp (cfg, lmfOffset + MONO_STRUCT_OFFSET (MonoLMF, gregs[0]), SLOT_NOREF);
5666 mini_gc_set_slot_type_from_fp (cfg, lmfOffset + MONO_STRUCT_OFFSET (MonoLMF, gregs[1]), SLOT_NOREF);
5667 mini_gc_set_slot_type_from_fp (cfg, lmfOffset + MONO_STRUCT_OFFSET (MonoLMF, gregs[2]), SLOT_NOREF);
5668 mini_gc_set_slot_type_from_fp (cfg, lmfOffset + MONO_STRUCT_OFFSET (MonoLMF, gregs[3]), SLOT_NOREF);
5669 mini_gc_set_slot_type_from_fp (cfg, lmfOffset + MONO_STRUCT_OFFSET (MonoLMF, gregs[4]), SLOT_NOREF);
5670 mini_gc_set_slot_type_from_fp (cfg, lmfOffset + MONO_STRUCT_OFFSET (MonoLMF, gregs[5]), SLOT_NOREF);
5671 mini_gc_set_slot_type_from_fp (cfg, lmfOffset + MONO_STRUCT_OFFSET (MonoLMF, gregs[6]), SLOT_NOREF);
5672 mini_gc_set_slot_type_from_fp (cfg, lmfOffset + MONO_STRUCT_OFFSET (MonoLMF, gregs[7]), SLOT_NOREF);
5673 mini_gc_set_slot_type_from_fp (cfg, lmfOffset + MONO_STRUCT_OFFSET (MonoLMF, gregs[8]), SLOT_NOREF);
5674 mini_gc_set_slot_type_from_fp (cfg, lmfOffset + MONO_STRUCT_OFFSET (MonoLMF, gregs[9]), SLOT_NOREF);
5675 mini_gc_set_slot_type_from_fp (cfg, lmfOffset + MONO_STRUCT_OFFSET (MonoLMF, gregs[10]), SLOT_NOREF);
5677 fpOffset = lmfOffset + MONO_STRUCT_OFFSET (MonoLMF, fregs[0]);
5678 for (i = 0; i < 16; i++) {
5679 s390_std (code, i, 0, s390_r13,
5680 G_STRUCT_OFFSET(MonoLMF, fregs[i]));
5681 mini_gc_set_slot_type_from_fp (cfg, fpOffset, SLOT_NOREF);
5682 fpOffset += sizeof(double);
5685 /*---------------------------------------------------------------*/
5686 /* Restore the parameter registers now that we've set up the lmf */
5687 /*---------------------------------------------------------------*/
5688 s390_lmg (code, s390_r2, s390_r6, s390_r13,
5689 G_STRUCT_OFFSET(MonoLMF, pregs[0]));
5692 if (cfg->method->save_lmf)
5693 argsClobbered = TRUE;
5696 * Optimize the common case of the first bblock making a call with the same
5697 * arguments as the method. This works because the arguments are still in their
5698 * original argument registers.
5700 if (!argsClobbered) {
5701 MonoBasicBlock *first_bb = cfg->bb_entry;
5702 MonoInst *next;
5703 int filter = FILTER_IL_SEQ_POINT;
5705 next = mono_bb_first_inst (first_bb, filter);
5706 if (!next && first_bb->next_bb) {
5707 first_bb = first_bb->next_bb;
5708 next = mono_bb_first_inst (first_bb, filter);
5711 if (first_bb->in_count > 1)
5712 next = NULL;
5714 for (i = 0; next && i < sig->param_count + sig->hasthis; ++i) {
5715 ArgInfo *ainfo = cinfo->args + i;
5716 gboolean match = FALSE;
5718 inst = cfg->args [i];
5719 if (inst->opcode != OP_REGVAR) {
5720 switch (ainfo->regtype) {
5721 case RegTypeGeneral: {
5722 if (((next->opcode == OP_LOAD_MEMBASE) ||
5723 (next->opcode == OP_LOADI4_MEMBASE)) &&
5724 next->inst_basereg == inst->inst_basereg &&
5725 next->inst_offset == inst->inst_offset) {
5726 if (next->dreg == ainfo->reg) {
5727 NULLIFY_INS (next);
5728 match = TRUE;
5729 } else {
5730 next->opcode = OP_MOVE;
5731 next->sreg1 = ainfo->reg;
5732 /* Only continue if the instruction doesn't change argument regs */
5733 if (next->dreg == ainfo->reg)
5734 match = TRUE;
5737 break;
5739 default:
5740 break;
5742 } else {
5743 /* Argument allocated to (non-volatile) register */
5744 switch (ainfo->regtype) {
5745 case RegTypeGeneral:
5746 if (next->opcode == OP_MOVE &&
5747 next->sreg1 == inst->dreg &&
5748 next->dreg == ainfo->reg) {
5749 NULLIFY_INS (next);
5750 match = TRUE;
5752 break;
5753 default:
5754 break;
5758 if (match) {
5759 next = mono_inst_next (next, filter);
5760 if (!next)
5761 break;
5766 set_code_cursor (cfg, code);
5768 return code;
5771 /*========================= End of Function ========================*/
5773 /*------------------------------------------------------------------*/
5774 /* */
5775 /* Name - mono_arch_emit_epilog */
5776 /* */
5777 /* Function - Emit the instructions for a function epilog. */
5778 /* */
5779 /*------------------------------------------------------------------*/
5781 void
5782 mono_arch_emit_epilog (MonoCompile *cfg)
5784 MonoMethod *method = cfg->method;
5785 guint8 *code;
5786 int max_epilog_size = 96;
5787 int fpOffset = 0;
5789 if (cfg->method->save_lmf)
5790 max_epilog_size += 128;
5792 code = realloc_code (cfg, max_epilog_size);
5794 if (method->save_lmf)
5795 restoreLMF(code, cfg->frame_reg, cfg->stack_usage);
5797 code = backUpStackPtr(cfg, code);
5799 if (cfg->arch.fpSize != 0) {
5800 fpOffset = -cfg->arch.fpSize;
5801 for (int i=8; i<16; i++) {
5802 if (cfg->arch.used_fp_regs & (1 << i)) {
5803 s390_ldy (code, i, 0, STK_BASE, fpOffset);
5804 fpOffset += sizeof(double);
5809 s390_lmg (code, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
5810 s390_br (code, s390_r14);
5812 set_code_cursor (cfg, code);
5816 /*========================= End of Function ========================*/
5818 /*------------------------------------------------------------------*/
5819 /* */
5820 /* Name - mono_arch_emit_exceptions */
5821 /* */
5822 /* Function - Emit the blocks to handle exception conditions. */
5823 /* */
5824 /*------------------------------------------------------------------*/
5826 void
5827 mono_arch_emit_exceptions (MonoCompile *cfg)
5829 MonoJumpInfo *patch_info;
5830 guint8 *code;
5831 int nThrows = 0,
5832 exc_count = 0,
5833 iExc;
5834 guint32 code_size;
5835 MonoClass *exc_classes [MAX_EXC];
5836 guint8 *exc_throw_start [MAX_EXC];
5838 for (patch_info = cfg->patch_info;
5839 patch_info;
5840 patch_info = patch_info->next) {
5841 if (patch_info->type == MONO_PATCH_INFO_EXC)
5842 exc_count++;
5845 code_size = exc_count * 48;
5847 code = realloc_code (cfg, code_size);
5849 /*---------------------------------------------------------------------*/
5850 /* Add code to raise exceptions */
5851 /*---------------------------------------------------------------------*/
5852 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5853 switch (patch_info->type) {
5854 case MONO_PATCH_INFO_EXC: {
5855 guint8 *ip = patch_info->ip.i + cfg->native_code;
5856 MonoClass *exc_class;
5857 guint64 throw_ip;
5859 /*-----------------------------------------------------*/
5860 /* Patch the branch in epilog to come here */
5861 /*-----------------------------------------------------*/
5862 s390_patch_rel (ip + 2, (guint64) S390_RELATIVE(code,ip));
5864 exc_class = mono_class_load_from_name (mono_defaults.corlib,
5865 "System",
5866 patch_info->data.name);
5867 throw_ip = patch_info->ip.i;
5869 for (iExc = 0; iExc < nThrows; ++iExc)
5870 if (exc_classes [iExc] == exc_class)
5871 break;
5873 if (iExc < nThrows) {
5874 s390_jcl (code, S390_CC_UN,
5875 (guint64) exc_throw_start [iExc]);
5876 patch_info->type = MONO_PATCH_INFO_NONE;
5877 } else {
5879 if (nThrows < MAX_EXC) {
5880 exc_classes [nThrows] = exc_class;
5881 exc_throw_start [nThrows] = code;
5884 /*---------------------------------------------*/
5885 /* Patch the parameter passed to the handler */
5886 /*---------------------------------------------*/
5887 S390_SET (code, s390_r2, m_class_get_type_token (exc_class));
5888 /*---------------------------------------------*/
5889 /* Load return address & parameter register */
5890 /*---------------------------------------------*/
5891 s390_larl (code, s390_r14, (guint64)S390_RELATIVE((patch_info->ip.i +
5892 cfg->native_code + 8), code));
5893 /*---------------------------------------------*/
5894 /* Reuse the current patch to set the jump */
5895 /*---------------------------------------------*/
5896 patch_info->type = MONO_PATCH_INFO_JIT_ICALL_ID;
5897 patch_info->data.jit_icall_id = MONO_JIT_ICALL_mono_arch_throw_corlib_exception;
5898 patch_info->ip.i = code - cfg->native_code;
5899 S390_BR_TEMPLATE (code, s390_r1);
5901 break;
5903 default:
5904 /* do nothing */
5905 break;
5908 set_code_cursor (cfg, code);
5911 /*========================= End of Function ========================*/
5913 /*------------------------------------------------------------------*/
5914 /* */
5915 /* Name - mono_arch_finish_init */
5916 /* */
5917 /* Function - Setup the JIT's Thread Level Specific Data. */
5918 /* */
5919 /*------------------------------------------------------------------*/
5921 void
5922 mono_arch_finish_init (void)
5926 /*========================= End of Function ========================*/
5928 /*========================= End of Function ========================*/
5930 /*------------------------------------------------------------------*/
5931 /* */
5932 /* Name - mono_arch_emit_inst_for_method */
5933 /* */
5934 /*------------------------------------------------------------------*/
5936 MonoInst*
5937 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5939 return NULL;
5942 /*========================= End of Function ========================*/
5944 /*------------------------------------------------------------------*/
5945 /* */
5946 /* Name - mono_arch_decompose_opts */
5947 /* */
5948 /* Function - Decompose opcode into a System z opcode. */
5949 /* */
5950 /*------------------------------------------------------------------*/
5952 void
5953 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
5956 * Have to rename these to avoid being decomposed normally, since the normal
5957 * decomposition does not work on S390.
5959 switch (ins->opcode) {
5960 case OP_ISUB_OVF:
5961 ins->opcode = OP_S390_ISUB_OVF;
5962 break;
5963 case OP_ISUB_OVF_UN:
5964 ins->opcode = OP_S390_ISUB_OVF_UN;
5965 break;
5966 case OP_IADD_OVF:
5967 ins->opcode = OP_S390_IADD_OVF;
5968 break;
5969 case OP_IADD_OVF_UN:
5970 ins->opcode = OP_S390_IADD_OVF_UN;
5971 break;
5972 case OP_LADD_OVF:
5973 ins->opcode = OP_S390_LADD_OVF;
5974 break;
5975 case OP_LADD_OVF_UN:
5976 ins->opcode = OP_S390_LADD_OVF_UN;
5977 break;
5978 case OP_LSUB_OVF:
5979 ins->opcode = OP_S390_LSUB_OVF;
5980 break;
5981 case OP_LSUB_OVF_UN:
5982 ins->opcode = OP_S390_LSUB_OVF_UN;
5983 break;
5984 default:
5985 break;
5989 /*========================= End of Function ========================*/
5991 /*------------------------------------------------------------------*/
5992 /* */
5993 /* Name - mono_arch_regalloc_cost */
5994 /* */
5995 /* Function - Determine the cost, in the number of memory */
5996 /* references, of the action of allocating the var- */
5997 /* iable VMV into a register during global register */
5998 /* allocation. */
5999 /* */
6000 /* Returns - Cost */
6001 /* */
6002 /*------------------------------------------------------------------*/
6004 guint32
6005 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
6007 /* FIXME: */
6008 return 2;
6011 /*========================= End of Function ========================*/
6013 /*------------------------------------------------------------------*/
6014 /* */
6015 /* Name - mono_arch_flush_register_windows */
6016 /* */
6017 /* Function - */
6018 /* */
6019 /* Returns - */
6020 /* */
6021 /*------------------------------------------------------------------*/
6023 void
6024 mono_arch_flush_register_windows (void)
6028 /*========================= End of Function ========================*/
6030 /*------------------------------------------------------------------*/
6031 /* */
6032 /* Name - mono_arch_is_inst_imm */
6033 /* */
6034 /* Function - Determine if operand qualifies as an immediate */
6035 /* value. For s390 this is a value -32768-32768 */
6036 /* */
6037 /* Returns - True|False - is [not] immediate value. */
6038 /* */
6039 /*------------------------------------------------------------------*/
6041 gboolean
6042 mono_arch_is_inst_imm (int opcode, int imm_opcode, gint64 imm)
6044 return s390_is_imm32 (imm);
6047 /*========================= End of Function ========================*/
6049 /*------------------------------------------------------------------*/
6050 /* */
6051 /* Name - mono_arch_get_patch_offset */
6052 /* */
6053 /* Function - Dummy entry point until s390x supports aot. */
6054 /* */
6055 /* Returns - Offset for patch. */
6056 /* */
6057 /*------------------------------------------------------------------*/
6059 guint32
6060 mono_arch_get_patch_offset (guint8 *code)
6062 return 0;
6065 /*========================= End of Function ========================*/
6067 /*------------------------------------------------------------------*/
6068 /* */
6069 /* Name - mono_arch_context_get_int_reg. */
6070 /* */
6071 /* Function - */
6072 /* */
6073 /* Returns - Return a register from the context. */
6074 /* */
6075 /*------------------------------------------------------------------*/
6077 host_mgreg_t
6078 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
6080 return ctx->uc_mcontext.gregs[reg];
6083 /*========================= End of Function ========================*/
6085 /*------------------------------------------------------------------*/
6086 /* */
6087 /* Name - mono_arch_context_set_int_reg. */
6088 /* */
6089 /* Function - Set a value in a specified register. */
6090 /* */
6091 /*------------------------------------------------------------------*/
6093 void
6094 mono_arch_context_set_int_reg (MonoContext *ctx, int reg, host_mgreg_t val)
6096 ctx->uc_mcontext.gregs[reg] = val;
6099 /*========================= End of Function ========================*/
6101 /*------------------------------------------------------------------*/
6102 /* */
6103 /* Name - mono_arch_get_this_arg_from_call. */
6104 /* */
6105 /* Function - */
6106 /* */
6107 /*------------------------------------------------------------------*/
6109 gpointer
6110 mono_arch_get_this_arg_from_call (host_mgreg_t *regs, guint8 *code)
6112 return (gpointer) regs [s390_r2];
6115 /*========================= End of Function ========================*/
6117 /*------------------------------------------------------------------*/
6118 /* */
6119 /* Name - get_delegate_invoke_impl. */
6120 /* */
6121 /* Function - */
6122 /* */
6123 /*------------------------------------------------------------------*/
6125 static guint8*
6126 get_delegate_invoke_impl (MonoTrampInfo **info, gboolean has_target, guint32 param_count, gboolean aot)
6128 guint8 *code, *start;
6130 if (has_target) {
6131 int size = 32;
6133 start = code = mono_global_codeman_reserve (size);
6135 /* Replace the this argument with the target */
6136 s390_lg (code, s390_r1, 0, s390_r2, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
6137 s390_lg (code, s390_r2, 0, s390_r2, MONO_STRUCT_OFFSET (MonoDelegate, target));
6138 s390_br (code, s390_r1);
6139 g_assert ((code - start) <= size);
6141 mono_arch_flush_icache (start, size);
6142 MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_DELEGATE_INVOKE, NULL));
6143 } else {
6144 int size, i;
6146 size = 32 + param_count * 8;
6147 start = code = mono_global_codeman_reserve (size);
6149 s390_lg (code, s390_r1, 0, s390_r2, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
6150 /* slide down the arguments */
6151 for (i = 0; i < param_count; ++i) {
6152 s390_lgr (code, (s390_r2 + i), (s390_r2 + i + 1));
6154 s390_br (code, s390_r1);
6156 g_assert ((code - start) <= size);
6158 mono_arch_flush_icache (start, size);
6159 MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_DELEGATE_INVOKE, NULL));
6162 if (has_target) {
6163 *info = mono_tramp_info_create ("delegate_invoke_impl_has_target", start, code - start, NULL, NULL);
6164 } else {
6165 char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", param_count);
6166 *info = mono_tramp_info_create (name, start, code - start, NULL, NULL);
6167 g_free (name);
6170 return start;
6173 /*========================= End of Function ========================*/
6175 /*------------------------------------------------------------------*/
6176 /* */
6177 /* Name - mono_arch_get_delegate_invoke_impls. */
6178 /* */
6179 /* Function - */
6180 /* */
6181 /*------------------------------------------------------------------*/
6183 GSList*
6184 mono_arch_get_delegate_invoke_impls (void)
6186 GSList *res = NULL;
6187 MonoTrampInfo *info;
6188 int i;
6190 get_delegate_invoke_impl (&info, TRUE, 0, TRUE);
6191 res = g_slist_prepend (res, info);
6193 for (i = 0; i <= MAX_ARCH_DELEGATE_PARAMS; ++i) {
6194 get_delegate_invoke_impl (&info, FALSE, i, TRUE);
6195 res = g_slist_prepend (res, info);
6198 return res;
6201 /*========================= End of Function ========================*/
6203 /*------------------------------------------------------------------*/
6204 /* */
6205 /* Name - mono_arch_get_delegate_invoke_impl. */
6206 /* */
6207 /* Function - */
6208 /* */
6209 /*------------------------------------------------------------------*/
6211 gpointer
6212 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
6214 guint8 *code, *start;
6216 /* FIXME: Support more cases */
6217 if (MONO_TYPE_ISSTRUCT (sig->ret))
6218 return NULL;
6220 if (has_target) {
6221 static guint8* cached = NULL;
6223 if (cached)
6224 return cached;
6226 if (mono_ee_features.use_aot_trampolines) {
6227 start = mono_aot_get_trampoline ("delegate_invoke_impl_has_target");
6228 } else {
6229 MonoTrampInfo *info;
6230 start = get_delegate_invoke_impl (&info, TRUE, 0, FALSE);
6231 mono_tramp_info_register (info, NULL);
6234 mono_memory_barrier ();
6236 cached = start;
6237 } else {
6238 static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
6239 int i;
6241 if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
6242 return NULL;
6243 for (i = 0; i < sig->param_count; ++i)
6244 if (!mono_is_regsize_var (sig->params [i]))
6245 return NULL;
6248 code = cache [sig->param_count];
6249 if (code)
6250 return code;
6252 if (mono_ee_features.use_aot_trampolines) {
6253 char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", sig->param_count);
6254 start = mono_aot_get_trampoline (name);
6255 g_free (name);
6256 } else {
6257 MonoTrampInfo *info;
6258 start = get_delegate_invoke_impl (&info, FALSE, sig->param_count, FALSE);
6259 mono_tramp_info_register (info, NULL);
6262 mono_memory_barrier ();
6264 cache [sig->param_count] = start;
6266 return start;
6269 /*========================= End of Function ========================*/
6271 /*------------------------------------------------------------------*/
6272 /* */
6273 /* Name - mono_arch_get_delegate_virtual_invoke_impl. */
6274 /* */
6275 /* Function - */
6276 /* */
6277 /*------------------------------------------------------------------*/
6279 gpointer
6280 mono_arch_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method,
6281 int offset, gboolean load_imt_reg)
6283 guint8 *code, *start;
6284 int size = 40;
6286 start = code = mono_global_codeman_reserve (size);
6289 * Replace the "this" argument with the target
6291 s390_lgr (code, s390_r1, s390_r2);
6292 s390_lg (code, s390_r2, 0, s390_r1, MONO_STRUCT_OFFSET(MonoDelegate, target));
6295 * Load the IMT register, if needed
6297 if (load_imt_reg) {
6298 s390_lg (code, MONO_ARCH_IMT_REG, 0, s390_r1, MONO_STRUCT_OFFSET(MonoDelegate, method));
6302 * Load the vTable
6304 s390_lg (code, s390_r1, 0, s390_r2, MONO_STRUCT_OFFSET(MonoObject, vtable));
6305 if (offset != 0) {
6306 s390_agfi(code, s390_r1, offset);
6308 s390_lg (code, s390_r1, 0, s390_r1, 0);
6309 s390_br (code, s390_r1);
6311 mono_arch_flush_icache (start, code - start);
6312 MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_DELEGATE_INVOKE, NULL));
6314 return(start);
6317 /*========================= End of Function ========================*/
6319 /*------------------------------------------------------------------*/
6320 /* */
6321 /* Name - mono_arch_build_imt_trampoline. */
6322 /* */
6323 /* Function - */
6324 /* */
6325 /*------------------------------------------------------------------*/
6327 gpointer
6328 mono_arch_build_imt_trampoline (MonoVTable *vtable, MonoDomain *domain,
6329 MonoIMTCheckItem **imt_entries, int count,
6330 gpointer fail_tramp)
6332 int i;
6333 int size = 0;
6334 guchar *code, *start;
6335 char trampName[64];
6337 for (i = 0; i < count; ++i) {
6338 MonoIMTCheckItem *item = imt_entries [i];
6339 if (item->is_equals) {
6340 if (item->check_target_idx) {
6341 if (!item->compare_done)
6342 item->chunk_size += CMP_SIZE + JUMP_SIZE;
6343 if (item->has_target_code)
6344 item->chunk_size += BR_SIZE + JUMP_SIZE + LOADCON_SIZE;
6345 else
6346 item->chunk_size += BR_SIZE + JUMP_SIZE + LOADCON_SIZE +
6347 LOAD_SIZE;
6348 } else {
6349 if (fail_tramp) {
6350 item->chunk_size += CMP_SIZE + 2 * BR_SIZE + JUMP_SIZE +
6351 2 * LOADCON_SIZE;
6352 if (!item->has_target_code)
6353 item->chunk_size += LOAD_SIZE;
6354 } else {
6355 item->chunk_size += LOADCON_SIZE + LOAD_SIZE + BR_SIZE;
6356 #if ENABLE_WRONG_METHOD_CHECK
6357 item->chunk_size += CMP_SIZE + JUMP_SIZE;
6358 #endif
6361 } else {
6362 item->chunk_size += CMP_SIZE + JUMP_SIZE;
6363 imt_entries [item->check_target_idx]->compare_done = TRUE;
6365 size += item->chunk_size;
6368 if (fail_tramp)
6369 code = mono_method_alloc_generic_virtual_trampoline (domain, size);
6370 else
6371 code = mono_domain_code_reserve (domain, size);
6373 start = code;
6375 for (i = 0; i < count; ++i) {
6376 MonoIMTCheckItem *item = imt_entries [i];
6377 item->code_target = (guint8 *) code;
6378 if (item->is_equals) {
6379 if (item->check_target_idx) {
6380 if (!item->compare_done) {
6381 S390_SET (code, s390_r0, item->key);
6382 s390_cgr (code, s390_r0, MONO_ARCH_IMT_REG);
6384 item->jmp_code = (guint8*) code;
6385 s390_jcl (code, S390_CC_NE, 0);
6387 if (item->has_target_code) {
6388 S390_SET (code, s390_r1, item->value.target_code);
6389 } else {
6390 S390_SET (code, s390_r1, (&(vtable->vtable [item->value.vtable_slot])));
6391 s390_lg (code, s390_r1, 0, s390_r1, 0);
6393 s390_br (code, s390_r1);
6394 } else {
6395 if (fail_tramp) {
6396 gint64 target;
6398 S390_SET (code, s390_r0, item->key);
6399 s390_cgr (code, s390_r0, MONO_ARCH_IMT_REG);
6400 item->jmp_code = (guint8*) code;
6401 s390_jcl (code, S390_CC_NE, 0);
6402 if (item->has_target_code) {
6403 S390_SET (code, s390_r1, item->value.target_code);
6404 } else {
6405 g_assert (vtable);
6406 S390_SET (code, s390_r1,
6407 (&(vtable->vtable [item->value.vtable_slot])));
6408 s390_lg (code, s390_r1, 0, s390_r1, 0);
6410 s390_br (code, s390_r1);
6411 target = (gint64) S390_RELATIVE(code, item->jmp_code);
6412 s390_patch_rel(item->jmp_code+2, target);
6413 S390_SET (code, s390_r1, fail_tramp);
6414 s390_br (code, s390_r1);
6415 item->jmp_code = NULL;
6416 } else {
6417 /* enable the commented code to assert on wrong method */
6418 #if ENABLE_WRONG_METHOD_CHECK
6419 g_assert_not_reached ();
6420 #endif
6421 S390_SET (code, s390_r1, (&(vtable->vtable [item->value.vtable_slot])));
6422 s390_lg (code, s390_r1, 0, s390_r1, 0);
6423 s390_br (code, s390_r1);
6426 } else {
6427 S390_SET (code, s390_r0, item->key);
6428 s390_cgr (code, MONO_ARCH_IMT_REG, s390_r0);
6429 item->jmp_code = (guint8 *) code;
6430 s390_jcl (code, S390_CC_GE, 0);
6434 * patch the branches to get to the target items
6436 for (i = 0; i < count; ++i) {
6437 MonoIMTCheckItem *item = imt_entries [i];
6438 if (item->jmp_code) {
6439 if (item->check_target_idx) {
6440 gint64 offset;
6441 offset = (gint64) S390_RELATIVE(imt_entries [item->check_target_idx]->code_target,
6442 item->jmp_code);
6443 s390_patch_rel ((guchar *) item->jmp_code + 2, (guint64) offset);
6448 mono_arch_flush_icache ((guint8*)start, (code - start));
6449 MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_IMT_TRAMPOLINE, NULL));
6451 if (!fail_tramp)
6452 UnlockedAdd (&mono_stats.imt_trampolines_size, code - start);
6454 g_assert (code - start <= size);
6456 snprintf(trampName, sizeof(trampName), "%d_imt_trampoline", domain->domain_id);
6457 mono_tramp_info_register (mono_tramp_info_create (trampName, start, code - start, NULL, NULL), domain);
6459 return (start);
6462 /*========================= End of Function ========================*/
6464 /*------------------------------------------------------------------*/
6465 /* */
6466 /* Name - mono_arch_find_imt_method. */
6467 /* */
6468 /* Function - Get the method address from MONO_ARCH_IMT_REG */
6469 /* found in the save area. */
6470 /* */
6471 /*------------------------------------------------------------------*/
6473 MonoMethod*
6474 mono_arch_find_imt_method (host_mgreg_t *regs, guint8 *code)
6476 return ((MonoMethod *) regs [MONO_ARCH_IMT_REG]);
6479 /*========================= End of Function ========================*/
6481 /*------------------------------------------------------------------*/
6482 /* */
6483 /* Name - mono_arch_find_static_call_vtable */
6484 /* */
6485 /* Function - Find the static call vtable. */
6486 /* */
6487 /*------------------------------------------------------------------*/
6489 MonoVTable*
6490 mono_arch_find_static_call_vtable (host_mgreg_t *regs, guint8 *code)
6492 return (MonoVTable*)(gsize) regs [MONO_ARCH_RGCTX_REG];
6495 /*========================= End of Function ========================*/
6497 /*------------------------------------------------------------------*/
6498 /* */
6499 /* Name - mono_arch_get_cie_program */
6500 /* */
6501 /* Function - Find the static call vtable. */
6502 /* */
6503 /*------------------------------------------------------------------*/
6505 GSList*
6506 mono_arch_get_cie_program (void)
6508 GSList *l = NULL;
6510 mono_add_unwind_op_def_cfa (l, 0, 0, STK_BASE, 0);
6512 return(l);
6515 /*========================= End of Function ========================*/
6517 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
6519 /*------------------------------------------------------------------*/
6520 /* */
6521 /* Name - mono_arch_set_breakpoint. */
6522 /* */
6523 /* Function - Set a breakpoint at the native code corresponding */
6524 /* to JI at NATIVE_OFFSET. The location should */
6525 /* contain code emitted by OP_SEQ_POINT. */
6526 /* */
6527 /*------------------------------------------------------------------*/
6529 void
6530 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
6532 guint8 *code = ip;
6534 breakpointCode.pTrigger = bp_trigger_page;
6535 memcpy(code, (void *) &breakpointCode, BREAKPOINT_SIZE);
6536 code += BREAKPOINT_SIZE;
6539 /*========================= End of Function ========================*/
6541 /*------------------------------------------------------------------*/
6542 /* */
6543 /* Name - mono_arch_clear_breakpoint. */
6544 /* */
6545 /* Function - Clear the breakpoint at IP. */
6546 /* */
6547 /*------------------------------------------------------------------*/
6549 void
6550 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
6552 guint8 *code = ip;
6553 int i;
6555 for (i = 0; i < (BREAKPOINT_SIZE / S390X_NOP_SIZE); i++)
6556 s390_nop(code);
6559 /*========================= End of Function ========================*/
6561 /*------------------------------------------------------------------*/
6562 /* */
6563 /* Name - mono_arch_is_breakpoint_event. */
6564 /* */
6565 /* Function - */
6566 /* */
6567 /*------------------------------------------------------------------*/
6569 gboolean
6570 mono_arch_is_breakpoint_event (void *info, void *sigctx)
6572 siginfo_t* sinfo = (siginfo_t*) info;
6575 * Sometimes the address is off by 4
6577 if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
6578 return TRUE;
6579 else
6580 return FALSE;
6583 /*========================= End of Function ========================*/
6585 /*------------------------------------------------------------------*/
6586 /* */
6587 /* Name - mono_arch_skip_breakpoint. */
6588 /* */
6589 /* Function - Modify the CTX so the IP is placed after the */
6590 /* breakpoint instruction, so when we resume, the */
6591 /* instruction is not executed again. */
6592 /* */
6593 /*------------------------------------------------------------------*/
6595 void
6596 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
6598 MONO_CONTEXT_SET_IP (ctx, ((guint8*)MONO_CONTEXT_GET_IP (ctx) + sizeof(RXY_Format)));
6601 /*========================= End of Function ========================*/
6603 /*------------------------------------------------------------------*/
6604 /* */
6605 /* Name - mono_arch_start_single_stepping. */
6606 /* */
6607 /* Function - Start single stepping. */
6608 /* */
6609 /*------------------------------------------------------------------*/
6611 void
6612 mono_arch_start_single_stepping (void)
6614 mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
6617 /*========================= End of Function ========================*/
6619 /*------------------------------------------------------------------*/
6620 /* */
6621 /* Name - mono_arch_stop_single_stepping. */
6622 /* */
6623 /* Function - Stop single stepping. */
6624 /* */
6625 /*------------------------------------------------------------------*/
6627 void
6628 mono_arch_stop_single_stepping (void)
6630 mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
6633 /*========================= End of Function ========================*/
6635 /*------------------------------------------------------------------*/
6636 /* */
6637 /* Name - mono_arch_is_single_step_event. */
6638 /* */
6639 /* Function - Return whether the machine state in sigctx cor- */
6640 /* responds to a single step event. */
6641 /* */
6642 /*------------------------------------------------------------------*/
6644 gboolean
6645 mono_arch_is_single_step_event (void *info, void *sigctx)
6647 siginfo_t* sinfo = (siginfo_t*) info;
6650 * Sometimes the address is off by 4
6652 if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
6653 return TRUE;
6654 else
6655 return FALSE;
6658 /*========================= End of Function ========================*/
6660 /*------------------------------------------------------------------*/
6661 /* */
6662 /* Name - mono_arch_skip_single_step. */
6663 /* */
6664 /* Function - Modify the ctx so the IP is placed after the */
6665 /* single step trigger instruction, so that the */
6666 /* instruction is not executed again. */
6667 /* */
6668 /*------------------------------------------------------------------*/
6670 void
6671 mono_arch_skip_single_step (MonoContext *ctx)
6673 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + BREAKPOINT_SIZE);
6676 /*========================= End of Function ========================*/
6678 /*------------------------------------------------------------------*/
6679 /* */
6680 /* Name - mono_arch_create_seq_point_info. */
6681 /* */
6682 /* Function - Return a pointer to a data struction which is */
6683 /* used by the sequence point implementation in */
6684 /* AOTed code. */
6685 /* */
6686 /*------------------------------------------------------------------*/
6688 SeqPointInfo*
6689 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
6691 NOT_IMPLEMENTED;
6692 return NULL;
6695 /*========================= End of Function ========================*/
6697 #endif
6699 /*------------------------------------------------------------------*/
6700 /* */
6701 /* Name - mono_arch_cpu_enumerate_simd_versions. */
6702 /* */
6703 /* Function - If this CPU supports vector operations then it */
6704 /* supports the equivalent of SSE1-4. */
6705 /* */
6706 /*------------------------------------------------------------------*/
6708 guint32
6709 mono_arch_cpu_enumerate_simd_versions (void)
6711 guint32 sseOpts = 0;
6713 if (mono_hwcap_s390x_has_vec)
6714 sseOpts = (SIMD_VERSION_SSE1 | SIMD_VERSION_SSE2 |
6715 SIMD_VERSION_SSE3 | SIMD_VERSION_SSSE3 |
6716 SIMD_VERSION_SSE41 | SIMD_VERSION_SSE42 |
6717 SIMD_VERSION_SSE4a);
6719 return (sseOpts);
6722 /*========================= End of Function ========================*/
6724 /*------------------------------------------------------------------*/
6725 /* */
6726 /* Name - mono_arch_opcode_supported. */
6727 /* */
6728 /* Function - Check if a given op code is supported. */
6729 /* */
6730 /*------------------------------------------------------------------*/
6732 gboolean
6733 mono_arch_opcode_supported (int opcode)
6735 switch (opcode) {
6736 case OP_ATOMIC_ADD_I4:
6737 case OP_ATOMIC_ADD_I8:
6738 case OP_ATOMIC_EXCHANGE_I4:
6739 case OP_ATOMIC_EXCHANGE_I8:
6740 return TRUE;
6741 default:
6742 return FALSE;
6746 /*========================= End of Function ========================*/
6748 /*------------------------------------------------------------------*/
6749 /* */
6750 /* Name - mono_arch_tailcall_supported. */
6751 /* */
6752 /* Function - Check if a tailcall is supported. */
6753 /* */
6754 /*------------------------------------------------------------------*/
6756 #ifndef DISABLE_JIT
6758 gboolean
6759 mono_arch_tailcall_supported (MonoCompile *cfg, MonoMethodSignature *caller_sig, MonoMethodSignature *callee_sig, gboolean virtual_)
6761 g_assert (caller_sig);
6762 g_assert (callee_sig);
6764 CallInfo *caller_info = get_call_info (NULL, caller_sig);
6765 CallInfo *callee_info = get_call_info (NULL, callee_sig);
6767 gboolean res = IS_SUPPORTED_TAILCALL (callee_info->stack_usage <= caller_info->stack_usage)
6768 && IS_SUPPORTED_TAILCALL (callee_info->struct_ret == caller_info->struct_ret)
6769 && IS_SUPPORTED_TAILCALL (memcmp (&callee_info->ret, &caller_info->ret, sizeof (caller_info->ret)) == 0);
6771 // valuetypes passed semantic-byvalue ABI-byref are often to a local.
6772 // FIXME ABIs vary as to if this local is in the parameter area or not,
6773 // so this check might not be needed.
6774 ArgInfo const * const ainfo = callee_info->args + callee_sig->hasthis;
6775 for (int i = 0; res && i < callee_sig->param_count; ++i) {
6776 res = IS_SUPPORTED_TAILCALL (ainfo [i].regtype != RegTypeStructByAddr)
6777 && IS_SUPPORTED_TAILCALL (ainfo [i].regtype != RegTypeStructByAddrOnStack);
6780 g_free (caller_info);
6781 g_free (callee_info);
6783 return res;
6786 #endif
6788 gpointer
6789 mono_arch_load_function (MonoJitICallId jit_icall_id)
6791 return NULL;
6794 /*========================= End of Function ========================*/