[ci] Bump timeout in ms-test-suite
[mono-project.git] / mono / mini / mini-mips.c
blobea7474dd28bbfbfdd1a6bf703467bf5e23b37141
1 /*
2 * mini-mips.c: MIPS backend for the Mono code generator
4 * Authors:
5 * Mark Mason (mason@broadcom.com)
7 * Based on mini-ppc.c by
8 * Paolo Molaro (lupus@ximian.com)
9 * Dietmar Maurer (dietmar@ximian.com)
11 * (C) 2006 Broadcom
12 * (C) 2003 Ximian, Inc.
14 #include "mini.h"
15 #include <string.h>
16 #include <asm/cachectl.h>
18 #include <mono/metadata/abi-details.h>
19 #include <mono/metadata/appdomain.h>
20 #include <mono/metadata/debug-helpers.h>
21 #include <mono/utils/mono-mmap.h>
22 #include <mono/utils/mono-hwcap.h>
24 #include <mono/arch/mips/mips-codegen.h>
26 #include "mini-mips.h"
27 #include "cpu-mips.h"
28 #include "trace.h"
29 #include "ir-emit.h"
31 #define SAVE_FP_REGS 0
33 #define ALWAYS_SAVE_RA 1 /* call-handler & switch currently clobber ra */
35 #define PROMOTE_R4_TO_R8 1 /* promote single values in registers to doubles */
36 #define USE_MUL 0 /* use mul instead of mult/mflo for multiply
37 remember to update cpu-mips.md if you change this */
39 /* Emit a call sequence to 'v', using 'D' as a scratch register if necessary */
40 #define mips_call(c,D,v) do { \
41 guint32 _target = (guint32)(v); \
42 if (1 || ((v) == NULL) || ((_target & 0xfc000000) != (((guint32)(c)) & 0xfc000000))) { \
43 mips_load_const (c, D, _target); \
44 mips_jalr (c, D, mips_ra); \
45 } \
46 else { \
47 mips_jumpl (c, _target >> 2); \
48 } \
49 mips_nop (c); \
50 } while (0)
52 enum {
53 TLS_MODE_DETECT,
54 TLS_MODE_FAILED,
55 TLS_MODE_LTHREADS,
56 TLS_MODE_NPTL
59 /* This mutex protects architecture specific caches */
60 #define mono_mini_arch_lock() mono_os_mutex_lock (&mini_arch_mutex)
61 #define mono_mini_arch_unlock() mono_os_mutex_unlock (&mini_arch_mutex)
62 static mono_mutex_t mini_arch_mutex;
64 int mono_exc_esp_offset = 0;
65 static int tls_mode = TLS_MODE_DETECT;
66 static int lmf_pthread_key = -1;
67 static int monothread_key = -1;
69 /* Whenever the host is little-endian */
70 static int little_endian;
71 /* Index of ms word/register */
72 static int ls_word_idx;
73 /* Index of ls word/register */
74 static int ms_word_idx;
75 /* Same for offsets */
76 static int ls_word_offset;
77 static int ms_word_offset;
80 * The code generated for sequence points reads from this location, which is
81 * made read-only when single stepping is enabled.
83 static gpointer ss_trigger_page;
85 /* Enabled breakpoints read from this trigger page */
86 static gpointer bp_trigger_page;
88 #undef DEBUG
89 #define DEBUG(a) if (cfg->verbose_level > 1) a
90 #undef DEBUG
91 #define DEBUG(a) a
92 #undef DEBUG
93 #define DEBUG(a)
95 #define EMIT_SYSTEM_EXCEPTION_NAME(exc_name) \
96 do { \
97 code = mips_emit_exc_by_name (code, exc_name); \
98 cfg->bb_exit->max_offset += 16; \
99 } while (0)
102 #define emit_linuxthreads_tls(code,dreg,key) do {\
103 int off1, off2; \
104 off1 = offsets_from_pthread_key ((key), &off2); \
105 g_assert_not_reached (); \
106 ppc_lwz ((code), (dreg), off1, ppc_r2); \
107 ppc_lwz ((code), (dreg), off2, (dreg)); \
108 } while (0);
111 #define emit_tls_access(code,dreg,key) do { \
112 switch (tls_mode) { \
113 case TLS_MODE_LTHREADS: emit_linuxthreads_tls(code,dreg,key); break; \
114 default: g_assert_not_reached (); \
116 } while (0)
118 #define MONO_EMIT_NEW_LOAD_R8(cfg,dr,addr) do { \
119 MonoInst *inst; \
120 MONO_INST_NEW ((cfg), (inst), OP_R8CONST); \
121 inst->type = STACK_R8; \
122 inst->dreg = (dr); \
123 inst->inst_p0 = (void*)(addr); \
124 mono_bblock_add_inst (cfg->cbb, inst); \
125 } while (0)
127 #define ins_is_compare(ins) ((ins) && (((ins)->opcode == OP_COMPARE) \
128 || ((ins)->opcode == OP_ICOMPARE) \
129 || ((ins)->opcode == OP_LCOMPARE)))
130 #define ins_is_compare_imm(ins) ((ins) && (((ins)->opcode == OP_COMPARE_IMM) \
131 || ((ins)->opcode == OP_ICOMPARE_IMM) \
132 || ((ins)->opcode == OP_LCOMPARE_IMM)))
134 #define INS_REWRITE(ins, op, _s1, _s2) do { \
135 int s1 = _s1; \
136 int s2 = _s2; \
137 ins->opcode = (op); \
138 ins->sreg1 = (s1); \
139 ins->sreg2 = (s2); \
140 } while (0);
142 #define INS_REWRITE_IMM(ins, op, _s1, _imm) do { \
143 int s1 = _s1; \
144 ins->opcode = (op); \
145 ins->sreg1 = (s1); \
146 ins->inst_imm = (_imm); \
147 } while (0);
150 typedef struct InstList InstList;
152 struct InstList {
153 InstList *prev;
154 InstList *next;
155 MonoInst *data;
158 typedef enum {
159 ArgInIReg,
160 ArgOnStack,
161 ArgInFReg,
162 ArgStructByVal,
163 ArgStructByAddr
164 } ArgStorage;
166 typedef struct {
167 gint32 offset;
168 guint16 vtsize; /* in param area */
169 guint8 reg;
170 ArgStorage storage;
171 guint8 size : 4; /* 1, 2, 4, 8, or regs used by ArgStructByVal */
172 } ArgInfo;
174 typedef struct {
175 int nargs;
176 int gr;
177 int fr;
178 gboolean gr_passed;
179 gboolean on_stack;
180 gboolean vtype_retaddr;
181 int stack_size;
182 guint32 stack_usage;
183 guint32 struct_ret;
184 ArgInfo ret;
185 ArgInfo sig_cookie;
186 ArgInfo args [1];
187 } CallInfo;
189 void patch_lui_addiu(guint32 *ip, guint32 val);
190 guint8 *mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code);
191 guint8 *mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins);
192 void mips_adjust_stackframe(MonoCompile *cfg);
193 void mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg);
194 MonoInst *mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args);
197 /* Not defined in asm/cachectl.h */
198 int cacheflush(char *addr, int nbytes, int cache);
200 void
201 mono_arch_flush_icache (guint8 *code, gint size)
203 /* Linux/MIPS specific */
204 cacheflush ((char*)code, size, BCACHE);
207 void
208 mono_arch_flush_register_windows (void)
212 gboolean
213 mono_arch_is_inst_imm (gint64 imm)
215 return TRUE;
218 static guint8 *
219 mips_emit_exc_by_name(guint8 *code, const char *name)
221 gpointer addr;
222 MonoClass *exc_class;
224 exc_class = mono_class_load_from_name (mono_defaults.corlib, "System", name);
226 mips_load_const (code, mips_a0, exc_class->type_token);
227 addr = mono_get_throw_corlib_exception ();
228 mips_call (code, mips_t9, addr);
229 return code;
233 guint8 *
234 mips_emit_load_const(guint8 *code, int dreg, mgreg_t v)
236 if (mips_is_imm16 (v))
237 mips_addiu (code, dreg, mips_zero, ((guint32)v) & 0xffff);
238 else {
239 #if SIZEOF_REGISTER == 8
240 if (v != (long) v) {
241 /* v is not a sign-extended 32-bit value */
242 mips_lui (code, dreg, mips_zero, (guint32)((v >> (32+16)) & 0xffff));
243 mips_ori (code, dreg, dreg, (guint32)((v >> (32)) & 0xffff));
244 mips_dsll (code, dreg, dreg, 16);
245 mips_ori (code, dreg, dreg, (guint32)((v >> (16)) & 0xffff));
246 mips_dsll (code, dreg, dreg, 16);
247 mips_ori (code, dreg, dreg, (guint32)(v & 0xffff));
248 return code;
250 #endif
251 if (((guint32)v) & (1 << 15)) {
252 mips_lui (code, dreg, mips_zero, (((guint32)v)>>16)+1);
254 else {
255 mips_lui (code, dreg, mips_zero, (((guint32)v)>>16));
257 if (((guint32)v) & 0xffff)
258 mips_addiu (code, dreg, dreg, ((guint32)v) & 0xffff);
260 return code;
263 guint8 *
264 mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins)
266 g_assert (ins);
267 if (cfg->arch.long_branch) {
268 int br_offset = 5;
270 /* Invert test and emit branch around jump */
271 switch (op) {
272 case OP_MIPS_BEQ:
273 mips_bne (code, ins->sreg1, ins->sreg2, br_offset);
274 mips_nop (code);
275 break;
276 case OP_MIPS_BNE:
277 mips_beq (code, ins->sreg1, ins->sreg2, br_offset);
278 mips_nop (code);
279 break;
280 case OP_MIPS_BGEZ:
281 mips_bltz (code, ins->sreg1, br_offset);
282 mips_nop (code);
283 break;
284 case OP_MIPS_BGTZ:
285 mips_blez (code, ins->sreg1, br_offset);
286 mips_nop (code);
287 break;
288 case OP_MIPS_BLEZ:
289 mips_bgtz (code, ins->sreg1, br_offset);
290 mips_nop (code);
291 break;
292 case OP_MIPS_BLTZ:
293 mips_bgez (code, ins->sreg1, br_offset);
294 mips_nop (code);
295 break;
296 default:
297 g_assert_not_reached ();
299 mono_add_patch_info (cfg, code - cfg->native_code,
300 MONO_PATCH_INFO_BB, ins->inst_true_bb);
301 mips_lui (code, mips_at, mips_zero, 0);
302 mips_addiu (code, mips_at, mips_at, 0);
303 mips_jr (code, mips_at);
304 mips_nop (code);
306 else {
307 mono_add_patch_info (cfg, code - cfg->native_code,
308 MONO_PATCH_INFO_BB, ins->inst_true_bb);
309 switch (op) {
310 case OP_MIPS_BEQ:
311 mips_beq (code, ins->sreg1, ins->sreg2, 0);
312 mips_nop (code);
313 break;
314 case OP_MIPS_BNE:
315 mips_bne (code, ins->sreg1, ins->sreg2, 0);
316 mips_nop (code);
317 break;
318 case OP_MIPS_BGEZ:
319 mips_bgez (code, ins->sreg1, 0);
320 mips_nop (code);
321 break;
322 case OP_MIPS_BGTZ:
323 mips_bgtz (code, ins->sreg1, 0);
324 mips_nop (code);
325 break;
326 case OP_MIPS_BLEZ:
327 mips_blez (code, ins->sreg1, 0);
328 mips_nop (code);
329 break;
330 case OP_MIPS_BLTZ:
331 mips_bltz (code, ins->sreg1, 0);
332 mips_nop (code);
333 break;
334 default:
335 g_assert_not_reached ();
338 return (code);
341 /* XXX - big-endian dependent? */
342 void
343 patch_lui_addiu(guint32 *ip, guint32 val)
345 guint16 *__lui_addiu = (guint16*)(void *)(ip);
347 #if 0
348 printf ("patch_lui_addiu ip=0x%08x (0x%08x, 0x%08x) to point to 0x%08x\n",
349 ip, ((guint32 *)ip)[0], ((guint32 *)ip)[1], val);
350 fflush (stdout);
351 #endif
352 if (((guint32)(val)) & (1 << 15))
353 __lui_addiu [MINI_LS_WORD_IDX] = ((((guint32)(val)) >> 16) & 0xffff) + 1;
354 else
355 __lui_addiu [MINI_LS_WORD_IDX] = (((guint32)(val)) >> 16) & 0xffff;
356 __lui_addiu [MINI_LS_WORD_IDX + 2] = ((guint32)(val)) & 0xffff;
357 mono_arch_flush_icache ((guint8 *)ip, 8);
360 guint32 trap_target;
361 void
362 mips_patch (guint32 *code, guint32 target)
364 guint32 ins = *code;
365 guint32 op = ins >> 26;
366 guint32 diff, offset;
368 g_assert (trap_target != target);
369 //printf ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
370 switch (op) {
371 case 0x00: /* jr ra */
372 if (ins == 0x3e00008)
373 break;
374 g_assert_not_reached ();
375 break;
376 case 0x02: /* j */
377 case 0x03: /* jal */
378 g_assert (!(target & 0x03));
379 g_assert ((target & 0xfc000000) == (((guint32)code) & 0xfc000000));
380 ins = (ins & 0xfc000000) | (((target) >> 2) & 0x03ffffff);
381 *code = ins;
382 mono_arch_flush_icache ((guint8 *)code, 4);
383 break;
384 case 0x01: /* BLTZ */
385 case 0x04: /* BEQ */
386 case 0x05: /* BNE */
387 case 0x06: /* BLEZ */
388 case 0x07: /* BGTZ */
389 case 0x11: /* bc1t */
390 diff = target - (guint32)(code + 1);
391 g_assert (((diff & 0x0003ffff) == diff) || ((diff | 0xfffc0000) == diff));
392 g_assert (!(diff & 0x03));
393 offset = ((gint32)diff) >> 2;
394 if (((int)offset) != ((int)(short)offset))
395 g_assert (((int)offset) == ((int)(short)offset));
396 ins = (ins & 0xffff0000) | (offset & 0x0000ffff);
397 *code = ins;
398 mono_arch_flush_icache ((guint8 *)code, 4);
399 break;
400 case 0x0f: /* LUI / ADDIU pair */
401 g_assert ((code[1] >> 26) == 0x9);
402 patch_lui_addiu (code, target);
403 mono_arch_flush_icache ((guint8 *)code, 8);
404 break;
406 default:
407 printf ("unknown op 0x%02x (0x%08x) @ %p\n", op, ins, code);
408 g_assert_not_reached ();
412 #if 0
413 static int
414 offsets_from_pthread_key (guint32 key, int *offset2)
416 int idx1 = key / 32;
417 int idx2 = key % 32;
418 *offset2 = idx2 * sizeof (gpointer);
419 return 284 + idx1 * sizeof (gpointer);
421 #endif
423 static void mono_arch_compute_omit_fp (MonoCompile *cfg);
425 const char*
426 mono_arch_regname (int reg) {
427 #if _MIPS_SIM == _ABIO32
428 static const char * rnames[] = {
429 "zero", "at", "v0", "v1",
430 "a0", "a1", "a2", "a3",
431 "t0", "t1", "t2", "t3",
432 "t4", "t5", "t6", "t7",
433 "s0", "s1", "s2", "s3",
434 "s4", "s5", "s6", "s7",
435 "t8", "t9", "k0", "k1",
436 "gp", "sp", "fp", "ra"
438 #elif _MIPS_SIM == _ABIN32
439 static const char * rnames[] = {
440 "zero", "at", "v0", "v1",
441 "a0", "a1", "a2", "a3",
442 "a4", "a5", "a6", "a7",
443 "t0", "t1", "t2", "t3",
444 "s0", "s1", "s2", "s3",
445 "s4", "s5", "s6", "s7",
446 "t8", "t9", "k0", "k1",
447 "gp", "sp", "fp", "ra"
449 #endif
450 if (reg >= 0 && reg < 32)
451 return rnames [reg];
452 return "unknown";
455 const char*
456 mono_arch_fregname (int reg) {
457 static const char * rnames[] = {
458 "f0", "f1", "f2", "f3",
459 "f4", "f5", "f6", "f7",
460 "f8", "f9", "f10", "f11",
461 "f12", "f13", "f14", "f15",
462 "f16", "f17", "f18", "f19",
463 "f20", "f21", "f22", "f23",
464 "f24", "f25", "f26", "f27",
465 "f28", "f29", "f30", "f31"
467 if (reg >= 0 && reg < 32)
468 return rnames [reg];
469 return "unknown";
472 /* this function overwrites at */
473 static guint8*
474 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
476 /* XXX write a loop, not an unrolled loop */
477 while (size > 0) {
478 mips_lw (code, mips_at, sreg, soffset);
479 mips_sw (code, mips_at, dreg, doffset);
480 size -= 4;
481 soffset += 4;
482 doffset += 4;
484 return code;
488 * mono_arch_get_argument_info:
489 * @csig: a method signature
490 * @param_count: the number of parameters to consider
491 * @arg_info: an array to store the result infos
493 * Gathers information on parameters such as size, alignment and
494 * padding. arg_info should be large enought to hold param_count + 1 entries.
496 * Returns the size of the activation frame.
499 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
501 int k, frame_size = 0;
502 guint32 size, align, pad;
503 int offset = 0;
505 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
506 frame_size += sizeof (gpointer);
507 offset += 4;
510 arg_info [0].offset = offset;
512 if (csig->hasthis) {
513 frame_size += sizeof (gpointer);
514 offset += 4;
517 arg_info [0].size = frame_size;
519 for (k = 0; k < param_count; k++) {
520 size = mini_type_stack_size_full (csig->params [k], &align, csig->pinvoke);
522 /* ignore alignment for now */
523 align = 1;
525 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
526 arg_info [k].pad = pad;
527 frame_size += size;
528 arg_info [k + 1].pad = 0;
529 arg_info [k + 1].size = size;
530 offset += pad;
531 arg_info [k + 1].offset = offset;
532 offset += size;
535 align = MONO_ARCH_FRAME_ALIGNMENT;
536 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
537 arg_info [k].pad = pad;
539 return frame_size;
542 /* The delegate object plus 3 params */
543 #define MAX_ARCH_DELEGATE_PARAMS (4 - 1)
545 static gpointer
546 get_delegate_invoke_impl (MonoTrampInfo **info, gboolean has_target, gboolean param_count)
548 guint8 *code, *start;
550 if (has_target) {
551 start = code = mono_global_codeman_reserve (16);
553 /* Replace the this argument with the target */
554 mips_lw (code, mips_temp, mips_a0, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
555 mips_lw (code, mips_a0, mips_a0, MONO_STRUCT_OFFSET (MonoDelegate, target));
556 mips_jr (code, mips_temp);
557 mips_nop (code);
559 g_assert ((code - start) <= 16);
561 mono_arch_flush_icache (start, 16);
562 } else {
563 int size, i;
565 size = 16 + param_count * 4;
566 start = code = mono_global_codeman_reserve (size);
568 mips_lw (code, mips_temp, mips_a0, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
569 /* slide down the arguments */
570 for (i = 0; i < param_count; ++i) {
571 mips_move (code, mips_a0 + i, mips_a0 + i + 1);
573 mips_jr (code, mips_temp);
574 mips_nop (code);
576 g_assert ((code - start) <= size);
578 mono_arch_flush_icache (start, size);
581 if (has_target) {
582 *info = mono_tramp_info_create ("delegate_invoke_impl_has_target", start, code - start, NULL, NULL);
583 } else {
584 char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", param_count);
585 *info = mono_tramp_info_create (name, start, code - start, NULL, NULL);
586 g_free (name);
589 return start;
593 * mono_arch_get_delegate_invoke_impls:
595 * Return a list of MonoAotTrampInfo structures for the delegate invoke impl
596 * trampolines.
598 GSList*
599 mono_arch_get_delegate_invoke_impls (void)
601 GSList *res = NULL;
602 MonoTrampInfo *info;
603 int i;
605 get_delegate_invoke_impl (&info, TRUE, 0);
606 res = g_slist_prepend (res, info);
608 for (i = 0; i <= MAX_ARCH_DELEGATE_PARAMS; ++i) {
609 get_delegate_invoke_impl (&info, FALSE, i);
610 res = g_slist_prepend (res, info);
613 return res;
616 gpointer
617 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
619 guint8 *code, *start;
621 /* FIXME: Support more cases */
622 if (MONO_TYPE_ISSTRUCT (sig->ret))
623 return NULL;
625 if (has_target) {
626 static guint8* cached = NULL;
627 mono_mini_arch_lock ();
628 if (cached) {
629 mono_mini_arch_unlock ();
630 return cached;
633 if (mono_aot_only) {
634 start = mono_aot_get_trampoline ("delegate_invoke_impl_has_target");
635 } else {
636 MonoTrampInfo *info;
637 start = get_delegate_invoke_impl (&info, TRUE, 0);
638 mono_tramp_info_register (info, NULL);
640 cached = start;
641 mono_mini_arch_unlock ();
642 return cached;
643 } else {
644 static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
645 int i;
647 if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
648 return NULL;
649 for (i = 0; i < sig->param_count; ++i)
650 if (!mono_is_regsize_var (sig->params [i]))
651 return NULL;
653 mono_mini_arch_lock ();
654 code = cache [sig->param_count];
655 if (code) {
656 mono_mini_arch_unlock ();
657 return code;
660 if (mono_aot_only) {
661 char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", sig->param_count);
662 start = mono_aot_get_trampoline (name);
663 g_free (name);
664 } else {
665 MonoTrampInfo *info;
666 start = get_delegate_invoke_impl (&info, FALSE, sig->param_count);
667 mono_tramp_info_register (info, NULL);
669 cache [sig->param_count] = start;
670 mono_mini_arch_unlock ();
671 return start;
674 return NULL;
677 gpointer
678 mono_arch_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method, int offset, gboolean load_imt_reg)
680 return NULL;
683 gpointer
684 mono_arch_get_this_arg_from_call (mgreg_t *regs, guint8 *code)
686 g_assert(regs);
687 return (gpointer)regs [mips_a0];
691 * Initialize the cpu to execute managed code.
693 void
694 mono_arch_cpu_init (void)
696 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
697 little_endian = 1;
698 ls_word_idx = 0;
699 ms_word_idx = 1;
700 #else
701 ls_word_idx = 1;
702 ms_word_idx = 0;
703 #endif
705 ls_word_offset = ls_word_idx * 4;
706 ms_word_offset = ms_word_idx * 4;
710 * Initialize architecture specific code.
712 void
713 mono_arch_init (void)
715 mono_os_mutex_init_recursive (&mini_arch_mutex);
717 ss_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT, MONO_MEM_ACCOUNT_OTHER);
718 bp_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT, MONO_MEM_ACCOUNT_OTHER);
719 mono_mprotect (bp_trigger_page, mono_pagesize (), 0);
723 * Cleanup architecture specific code.
725 void
726 mono_arch_cleanup (void)
728 mono_os_mutex_destroy (&mini_arch_mutex);
732 * This function returns the optimizations supported on this cpu.
734 guint32
735 mono_arch_cpu_optimizations (guint32 *exclude_mask)
737 guint32 opts = 0;
739 /* no mips-specific optimizations yet */
740 *exclude_mask = 0;
741 return opts;
745 * This function test for all SIMD functions supported.
747 * Returns a bitmask corresponding to all supported versions.
750 guint32
751 mono_arch_cpu_enumerate_simd_versions (void)
753 /* SIMD is currently unimplemented */
754 return 0;
757 GList *
758 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
760 GList *vars = NULL;
761 int i;
763 for (i = 0; i < cfg->num_varinfo; i++) {
764 MonoInst *ins = cfg->varinfo [i];
765 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
767 /* unused vars */
768 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
769 continue;
771 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
772 continue;
774 /* we can only allocate 32 bit values */
775 if (mono_is_regsize_var (ins->inst_vtype)) {
776 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
777 g_assert (i == vmv->idx);
778 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
782 return vars;
785 GList *
786 mono_arch_get_global_int_regs (MonoCompile *cfg)
788 GList *regs = NULL;
790 regs = g_list_prepend (regs, (gpointer)mips_s0);
791 regs = g_list_prepend (regs, (gpointer)mips_s1);
792 regs = g_list_prepend (regs, (gpointer)mips_s2);
793 regs = g_list_prepend (regs, (gpointer)mips_s3);
794 regs = g_list_prepend (regs, (gpointer)mips_s4);
795 //regs = g_list_prepend (regs, (gpointer)mips_s5);
796 regs = g_list_prepend (regs, (gpointer)mips_s6);
797 regs = g_list_prepend (regs, (gpointer)mips_s7);
799 return regs;
803 * mono_arch_regalloc_cost:
805 * Return the cost, in number of memory references, of the action of
806 * allocating the variable VMV into a register during global register
807 * allocation.
809 guint32
810 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
812 /* FIXME: */
813 return 2;
816 static void
817 args_onto_stack (CallInfo *info)
819 g_assert (!info->on_stack);
820 g_assert (info->stack_size <= MIPS_STACK_PARAM_OFFSET);
821 info->on_stack = TRUE;
822 info->stack_size = MIPS_STACK_PARAM_OFFSET;
825 #if _MIPS_SIM == _ABIO32
827 * O32 calling convention version
830 static void
831 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
832 /* First, see if we need to drop onto the stack */
833 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
834 args_onto_stack (info);
836 /* Now, place the argument */
837 if (info->on_stack) {
838 ainfo->storage = ArgOnStack;
839 ainfo->reg = mips_sp; /* in the caller */
840 ainfo->offset = info->stack_size;
842 else {
843 ainfo->storage = ArgInIReg;
844 ainfo->reg = info->gr;
845 info->gr += 1;
846 info->gr_passed = TRUE;
848 info->stack_size += 4;
851 static void
852 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
853 /* First, see if we need to drop onto the stack */
854 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
855 args_onto_stack (info);
857 /* Now, place the argument */
858 if (info->on_stack) {
859 g_assert (info->stack_size % 4 == 0);
860 info->stack_size += (info->stack_size % 8);
862 ainfo->storage = ArgOnStack;
863 ainfo->reg = mips_sp; /* in the caller */
864 ainfo->offset = info->stack_size;
866 else {
867 // info->gr must be a0 or a2
868 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
869 g_assert(info->gr <= MIPS_LAST_ARG_REG);
871 ainfo->storage = ArgInIReg;
872 ainfo->reg = info->gr;
873 info->gr += 2;
874 info->gr_passed = TRUE;
876 info->stack_size += 8;
879 static void
880 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
881 /* First, see if we need to drop onto the stack */
882 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
883 args_onto_stack (info);
885 /* Now, place the argument */
886 if (info->on_stack) {
887 ainfo->storage = ArgOnStack;
888 ainfo->reg = mips_sp; /* in the caller */
889 ainfo->offset = info->stack_size;
891 else {
892 /* Only use FP regs for args if no int args passed yet */
893 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
894 ainfo->storage = ArgInFReg;
895 ainfo->reg = info->fr;
896 /* Even though it's a single-precision float, it takes up two FP regs */
897 info->fr += 2;
898 /* FP and GP slots do not overlap */
899 info->gr += 1;
901 else {
902 /* Passing single-precision float arg in a GP register
903 * such as: func (0, 1.0, 2, 3);
904 * In this case, only one 'gr' register is consumed.
906 ainfo->storage = ArgInIReg;
907 ainfo->reg = info->gr;
909 info->gr += 1;
910 info->gr_passed = TRUE;
913 info->stack_size += 4;
916 static void
917 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
918 /* First, see if we need to drop onto the stack */
919 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
920 args_onto_stack (info);
922 /* Now, place the argument */
923 if (info->on_stack) {
924 g_assert(info->stack_size % 4 == 0);
925 info->stack_size += (info->stack_size % 8);
927 ainfo->storage = ArgOnStack;
928 ainfo->reg = mips_sp; /* in the caller */
929 ainfo->offset = info->stack_size;
931 else {
932 /* Only use FP regs for args if no int args passed yet */
933 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
934 ainfo->storage = ArgInFReg;
935 ainfo->reg = info->fr;
936 info->fr += 2;
937 /* FP and GP slots do not overlap */
938 info->gr += 2;
940 else {
941 // info->gr must be a0 or a2
942 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
943 g_assert(info->gr <= MIPS_LAST_ARG_REG);
945 ainfo->storage = ArgInIReg;
946 ainfo->reg = info->gr;
947 info->gr += 2;
948 info->gr_passed = TRUE;
951 info->stack_size += 8;
953 #elif _MIPS_SIM == _ABIN32
955 * N32 calling convention version
958 static void
959 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
960 /* First, see if we need to drop onto the stack */
961 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
962 args_onto_stack (info);
964 /* Now, place the argument */
965 if (info->on_stack) {
966 ainfo->storage = ArgOnStack;
967 ainfo->reg = mips_sp; /* in the caller */
968 ainfo->offset = info->stack_size;
969 info->stack_size += SIZEOF_REGISTER;
971 else {
972 ainfo->storage = ArgInIReg;
973 ainfo->reg = info->gr;
974 info->gr += 1;
975 info->gr_passed = TRUE;
979 static void
980 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
981 /* First, see if we need to drop onto the stack */
982 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
983 args_onto_stack (info);
985 /* Now, place the argument */
986 if (info->on_stack) {
987 g_assert (info->stack_size % 4 == 0);
988 info->stack_size += (info->stack_size % 8);
990 ainfo->storage = ArgOnStack;
991 ainfo->reg = mips_sp; /* in the caller */
992 ainfo->offset = info->stack_size;
993 info->stack_size += SIZEOF_REGISTER;
995 else {
996 g_assert (info->gr <= MIPS_LAST_ARG_REG);
998 ainfo->storage = ArgInIReg;
999 ainfo->reg = info->gr;
1000 info->gr += 1;
1001 info->gr_passed = TRUE;
1005 static void
1006 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
1007 /* First, see if we need to drop onto the stack */
1008 if (!info->on_stack) {
1009 if (info->gr > MIPS_LAST_ARG_REG)
1010 args_onto_stack (info);
1011 else if (info->fr > MIPS_LAST_FPARG_REG)
1012 args_onto_stack (info);
1015 /* Now, place the argument */
1016 if (info->on_stack) {
1017 ainfo->storage = ArgOnStack;
1018 ainfo->reg = mips_sp; /* in the caller */
1019 ainfo->offset = info->stack_size;
1020 info->stack_size += FREG_SIZE;
1022 else {
1023 ainfo->storage = ArgInFReg;
1024 ainfo->reg = info->fr;
1025 info->fr += 1;
1026 /* FP and GP slots do not overlap */
1027 info->gr += 1;
1031 static void
1032 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
1033 /* First, see if we need to drop onto the stack */
1034 if (!info->on_stack) {
1035 if (info->gr > MIPS_LAST_ARG_REG)
1036 args_onto_stack (info);
1037 else if (info->fr > MIPS_LAST_FPARG_REG)
1038 args_onto_stack (info);
1041 /* Now, place the argument */
1042 if (info->on_stack) {
1043 g_assert(info->stack_size % 4 == 0);
1044 info->stack_size += (info->stack_size % 8);
1046 ainfo->storage = ArgOnStack;
1047 ainfo->reg = mips_sp; /* in the caller */
1048 ainfo->offset = info->stack_size;
1049 info->stack_size += FREG_SIZE;
1051 else {
1052 ainfo->storage = ArgInFReg;
1053 ainfo->reg = info->fr;
1054 info->fr += 1;
1055 /* FP and GP slots do not overlap */
1056 info->gr += 1;
1059 #endif
1061 static CallInfo*
1062 get_call_info (MonoMemPool *mp, MonoMethodSignature *sig)
1064 guint i;
1065 int n = sig->hasthis + sig->param_count;
1066 int pstart;
1067 MonoType* simpletype;
1068 CallInfo *cinfo;
1069 gboolean is_pinvoke = sig->pinvoke;
1071 if (mp)
1072 cinfo = mono_mempool_alloc0 (mp, sizeof (CallInfo) + (sizeof (ArgInfo) * n));
1073 else
1074 cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
1076 cinfo->fr = MIPS_FIRST_FPARG_REG;
1077 cinfo->gr = MIPS_FIRST_ARG_REG;
1078 cinfo->stack_size = 0;
1080 DEBUG(printf("calculate_sizes\n"));
1082 cinfo->vtype_retaddr = MONO_TYPE_ISSTRUCT (sig->ret) ? TRUE : FALSE;
1083 pstart = 0;
1084 n = 0;
1085 #if 0
1086 /* handle returning a struct */
1087 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1088 cinfo->struct_ret = cinfo->gr;
1089 add_int32_arg (cinfo, &cinfo->ret);
1092 if (sig->hasthis) {
1093 add_int32_arg (cinfo, cinfo->args + n);
1094 n++;
1096 #else
1098 * To simplify get_this_arg_reg () and LLVM integration, emit the vret arg after
1099 * the first argument, allowing 'this' to be always passed in the first arg reg.
1100 * Also do this if the first argument is a reference type, since virtual calls
1101 * are sometimes made using calli without sig->hasthis set, like in the delegate
1102 * invoke wrappers.
1104 if (cinfo->vtype_retaddr && !is_pinvoke && (sig->hasthis || (sig->param_count > 0 && MONO_TYPE_IS_REFERENCE (mini_get_underlying_type (sig->params [0]))))) {
1105 if (sig->hasthis) {
1106 add_int32_arg (cinfo, cinfo->args + n);
1107 n ++;
1108 } else {
1109 add_int32_arg (cinfo, cinfo->args + sig->hasthis);
1110 pstart = 1;
1111 n ++;
1113 add_int32_arg (cinfo, &cinfo->ret);
1114 cinfo->struct_ret = cinfo->ret.reg;
1115 } else {
1116 /* this */
1117 if (sig->hasthis) {
1118 add_int32_arg (cinfo, cinfo->args + n);
1119 n ++;
1122 if (cinfo->vtype_retaddr) {
1123 add_int32_arg (cinfo, &cinfo->ret);
1124 cinfo->struct_ret = cinfo->ret.reg;
1127 #endif
1129 DEBUG(printf("params: %d\n", sig->param_count));
1130 for (i = pstart; i < sig->param_count; ++i) {
1131 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1132 /* Prevent implicit arguments and sig_cookie from
1133 being passed in registers */
1134 args_onto_stack (cinfo);
1135 /* Emit the signature cookie just before the implicit arguments */
1136 add_int32_arg (cinfo, &cinfo->sig_cookie);
1138 DEBUG(printf("param %d: ", i));
1139 simpletype = mini_get_underlying_type (sig->params [i]);
1140 switch (simpletype->type) {
1141 case MONO_TYPE_BOOLEAN:
1142 case MONO_TYPE_I1:
1143 case MONO_TYPE_U1:
1144 DEBUG(printf("1 byte\n"));
1145 cinfo->args [n].size = 1;
1146 add_int32_arg (cinfo, &cinfo->args[n]);
1147 n++;
1148 break;
1149 case MONO_TYPE_CHAR:
1150 case MONO_TYPE_I2:
1151 case MONO_TYPE_U2:
1152 DEBUG(printf("2 bytes\n"));
1153 cinfo->args [n].size = 2;
1154 add_int32_arg (cinfo, &cinfo->args[n]);
1155 n++;
1156 break;
1157 case MONO_TYPE_I4:
1158 case MONO_TYPE_U4:
1159 DEBUG(printf("4 bytes\n"));
1160 cinfo->args [n].size = 4;
1161 add_int32_arg (cinfo, &cinfo->args[n]);
1162 n++;
1163 break;
1164 case MONO_TYPE_I:
1165 case MONO_TYPE_U:
1166 case MONO_TYPE_PTR:
1167 case MONO_TYPE_FNPTR:
1168 case MONO_TYPE_CLASS:
1169 case MONO_TYPE_OBJECT:
1170 case MONO_TYPE_STRING:
1171 case MONO_TYPE_SZARRAY:
1172 case MONO_TYPE_ARRAY:
1173 cinfo->args [n].size = sizeof (gpointer);
1174 add_int32_arg (cinfo, &cinfo->args[n]);
1175 n++;
1176 break;
1177 case MONO_TYPE_GENERICINST:
1178 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1179 cinfo->args [n].size = sizeof (gpointer);
1180 add_int32_arg (cinfo, &cinfo->args[n]);
1181 n++;
1182 break;
1184 /* Fall through */
1185 case MONO_TYPE_TYPEDBYREF:
1186 case MONO_TYPE_VALUETYPE: {
1187 int j;
1188 int nwords = 0;
1189 int has_offset = FALSE;
1190 ArgInfo dummy_arg;
1191 gint size, alignment;
1192 MonoClass *klass;
1194 if (simpletype->type == MONO_TYPE_TYPEDBYREF) {
1195 size = sizeof (MonoTypedRef);
1196 alignment = sizeof (gpointer);
1197 } else {
1198 klass = mono_class_from_mono_type (sig->params [i]);
1199 if (is_pinvoke)
1200 size = mono_class_native_size (klass, NULL);
1201 else
1202 size = mono_class_value_size (klass, NULL);
1203 alignment = mono_class_min_align (klass);
1205 #if MIPS_PASS_STRUCTS_BY_VALUE
1206 /* Need to do alignment if struct contains long or double */
1207 if (alignment > 4) {
1208 /* Drop onto stack *before* looking at
1209 stack_size, if required. */
1210 if (!cinfo->on_stack && cinfo->gr > MIPS_LAST_ARG_REG)
1211 args_onto_stack (cinfo);
1212 if (cinfo->stack_size & (alignment - 1)) {
1213 add_int32_arg (cinfo, &dummy_arg);
1215 g_assert (!(cinfo->stack_size & (alignment - 1)));
1218 #if 0
1219 g_printf ("valuetype struct size=%d offset=%d align=%d\n",
1220 mono_class_native_size (sig->params [i]->data.klass, NULL),
1221 cinfo->stack_size, alignment);
1222 #endif
1223 nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
1224 g_assert (cinfo->args [n].size == 0);
1225 g_assert (cinfo->args [n].vtsize == 0);
1226 for (j = 0; j < nwords; ++j) {
1227 if (j == 0) {
1228 add_int32_arg (cinfo, &cinfo->args [n]);
1229 if (cinfo->on_stack)
1230 has_offset = TRUE;
1231 } else {
1232 add_int32_arg (cinfo, &dummy_arg);
1233 if (!has_offset && cinfo->on_stack) {
1234 cinfo->args [n].offset = dummy_arg.offset;
1235 has_offset = TRUE;
1238 if (cinfo->on_stack)
1239 cinfo->args [n].vtsize += 1;
1240 else
1241 cinfo->args [n].size += 1;
1243 //g_printf ("\tstack_size=%d vtsize=%d\n", cinfo->args [n].size, cinfo->args[n].vtsize);
1244 cinfo->args [n].storage = ArgStructByVal;
1245 #else
1246 add_int32_arg (cinfo, &cinfo->args[n]);
1247 cinfo->args [n].storage = ArgStructByAddr;
1248 #endif
1249 n++;
1250 break;
1252 case MONO_TYPE_U8:
1253 case MONO_TYPE_I8:
1254 DEBUG(printf("8 bytes\n"));
1255 cinfo->args [n].size = 8;
1256 add_int64_arg (cinfo, &cinfo->args[n]);
1257 n++;
1258 break;
1259 case MONO_TYPE_R4:
1260 DEBUG(printf("R4\n"));
1261 cinfo->args [n].size = 4;
1262 add_float32_arg (cinfo, &cinfo->args[n]);
1263 n++;
1264 break;
1265 case MONO_TYPE_R8:
1266 DEBUG(printf("R8\n"));
1267 cinfo->args [n].size = 8;
1268 add_float64_arg (cinfo, &cinfo->args[n]);
1269 n++;
1270 break;
1271 default:
1272 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
1276 /* Handle the case where there are no implicit arguments */
1277 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1278 /* Prevent implicit arguments and sig_cookie from
1279 being passed in registers */
1280 args_onto_stack (cinfo);
1281 /* Emit the signature cookie just before the implicit arguments */
1282 add_int32_arg (cinfo, &cinfo->sig_cookie);
1286 simpletype = mini_get_underlying_type (sig->ret);
1287 switch (simpletype->type) {
1288 case MONO_TYPE_BOOLEAN:
1289 case MONO_TYPE_I1:
1290 case MONO_TYPE_U1:
1291 case MONO_TYPE_I2:
1292 case MONO_TYPE_U2:
1293 case MONO_TYPE_CHAR:
1294 case MONO_TYPE_I4:
1295 case MONO_TYPE_U4:
1296 case MONO_TYPE_I:
1297 case MONO_TYPE_U:
1298 case MONO_TYPE_PTR:
1299 case MONO_TYPE_FNPTR:
1300 case MONO_TYPE_CLASS:
1301 case MONO_TYPE_OBJECT:
1302 case MONO_TYPE_SZARRAY:
1303 case MONO_TYPE_ARRAY:
1304 case MONO_TYPE_STRING:
1305 cinfo->ret.reg = mips_v0;
1306 break;
1307 case MONO_TYPE_U8:
1308 case MONO_TYPE_I8:
1309 cinfo->ret.reg = mips_v0;
1310 break;
1311 case MONO_TYPE_R4:
1312 case MONO_TYPE_R8:
1313 cinfo->ret.reg = mips_f0;
1314 cinfo->ret.storage = ArgInFReg;
1315 break;
1316 case MONO_TYPE_GENERICINST:
1317 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1318 cinfo->ret.reg = mips_v0;
1319 break;
1321 break;
1322 case MONO_TYPE_VALUETYPE:
1323 case MONO_TYPE_TYPEDBYREF:
1324 break;
1325 case MONO_TYPE_VOID:
1326 break;
1327 default:
1328 g_error ("Can't handle as return value 0x%x", sig->ret->type);
1332 /* align stack size to 16 */
1333 cinfo->stack_size = (cinfo->stack_size + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1335 cinfo->stack_usage = cinfo->stack_size;
1336 return cinfo;
1339 static gboolean
1340 debug_omit_fp (void)
1342 #if 0
1343 return mono_debug_count ();
1344 #else
1345 return TRUE;
1346 #endif
1350 * mono_arch_compute_omit_fp:
1352 * Determine whenever the frame pointer can be eliminated.
1354 static void
1355 mono_arch_compute_omit_fp (MonoCompile *cfg)
1357 MonoMethodSignature *sig;
1358 MonoMethodHeader *header;
1359 int i, locals_size;
1360 CallInfo *cinfo;
1362 if (cfg->arch.omit_fp_computed)
1363 return;
1365 header = cfg->header;
1367 sig = mono_method_signature (cfg->method);
1369 if (!cfg->arch.cinfo)
1370 cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
1371 cinfo = cfg->arch.cinfo;
1374 * FIXME: Remove some of the restrictions.
1376 cfg->arch.omit_fp = TRUE;
1377 cfg->arch.omit_fp_computed = TRUE;
1379 if (cfg->disable_omit_fp)
1380 cfg->arch.omit_fp = FALSE;
1381 if (!debug_omit_fp ())
1382 cfg->arch.omit_fp = FALSE;
1383 if (cfg->method->save_lmf)
1384 cfg->arch.omit_fp = FALSE;
1385 if (cfg->flags & MONO_CFG_HAS_ALLOCA)
1386 cfg->arch.omit_fp = FALSE;
1387 if (header->num_clauses)
1388 cfg->arch.omit_fp = FALSE;
1389 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
1390 cfg->arch.omit_fp = FALSE;
1391 if ((mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method)) ||
1392 (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE))
1393 cfg->arch.omit_fp = FALSE;
1395 * On MIPS, fp points to the bottom of the frame, so it can be eliminated even if
1396 * there are stack arguments.
1399 if (cinfo->stack_usage)
1400 cfg->arch.omit_fp = FALSE;
1403 locals_size = 0;
1404 for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
1405 MonoInst *ins = cfg->varinfo [i];
1406 int ialign;
1408 locals_size += mono_type_size (ins->inst_vtype, &ialign);
1411 //printf ("D: %s %d\n", cfg->method->name, cfg->arch.omit_fp);
1415 * Set var information according to the calling convention. mips version.
1416 * The locals var stuff should most likely be split in another method.
1418 void
1419 mono_arch_allocate_vars (MonoCompile *cfg)
1421 MonoMethodSignature *sig;
1422 MonoMethodHeader *header;
1423 MonoInst *inst;
1424 int i, offset, size, align, curinst;
1425 int frame_reg = mips_sp;
1426 guint32 iregs_to_save = 0;
1427 #if SAVE_FP_REGS
1428 guint32 fregs_to_restore;
1429 #endif
1430 CallInfo *cinfo;
1432 sig = mono_method_signature (cfg->method);
1434 if (!cfg->arch.cinfo)
1435 cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
1436 cinfo = cfg->arch.cinfo;
1438 mono_arch_compute_omit_fp (cfg);
1440 /* spill down, we'll fix it in a separate pass */
1441 // cfg->flags |= MONO_CFG_HAS_SPILLUP;
1443 /* allow room for the vararg method args: void* and long/double */
1444 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1445 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1447 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1448 * call convs needs to be handled this way.
1450 if (cfg->flags & MONO_CFG_HAS_VARARGS)
1451 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1453 /* gtk-sharp and other broken code will dllimport vararg functions even with
1454 * non-varargs signatures. Since there is little hope people will get this right
1455 * we assume they won't.
1457 if (cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1458 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1460 /* a0-a3 always present */
1461 cfg->param_area = MAX (cfg->param_area, MIPS_STACK_PARAM_OFFSET);
1463 header = cfg->header;
1465 if (cfg->arch.omit_fp)
1466 frame_reg = mips_sp;
1467 else
1468 frame_reg = mips_fp;
1469 cfg->frame_reg = frame_reg;
1470 if (frame_reg != mips_sp) {
1471 cfg->used_int_regs |= 1 << frame_reg;
1474 offset = 0;
1475 curinst = 0;
1476 if (!MONO_TYPE_ISSTRUCT (sig->ret)) {
1477 /* FIXME: handle long and FP values */
1478 switch (mini_get_underlying_type (sig->ret)->type) {
1479 case MONO_TYPE_VOID:
1480 break;
1481 case MONO_TYPE_R4:
1482 case MONO_TYPE_R8:
1483 cfg->ret->opcode = OP_REGVAR;
1484 cfg->ret->inst_c0 = cfg->ret->dreg = mips_f0;
1485 break;
1486 default:
1487 cfg->ret->opcode = OP_REGVAR;
1488 cfg->ret->inst_c0 = mips_v0;
1489 break;
1492 /* Space for outgoing parameters, including a0-a3 */
1493 offset += cfg->param_area;
1495 /* allow room to save the return value (if it's a struct) */
1496 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1497 offset += 8;
1499 /* Now handle the local variables */
1501 curinst = cfg->locals_start;
1502 for (i = curinst; i < cfg->num_varinfo; ++i) {
1503 inst = cfg->varinfo [i];
1504 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
1505 continue;
1507 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
1508 * pinvoke wrappers when they call functions returning structure
1510 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
1511 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), (unsigned int *) &align);
1512 else
1513 size = mono_type_size (inst->inst_vtype, &align);
1515 offset += align - 1;
1516 offset &= ~(align - 1);
1517 inst->inst_offset = offset;
1518 inst->opcode = OP_REGOFFSET;
1519 inst->inst_basereg = frame_reg;
1520 offset += size;
1521 // g_print ("allocating local %d to %d\n", i, inst->inst_offset);
1524 /* Space for LMF (if needed) */
1525 if (cfg->method->save_lmf) {
1526 /* align the offset to 16 bytes */
1527 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1528 cfg->arch.lmf_offset = offset;
1529 offset += sizeof (MonoLMF);
1532 if (sig->call_convention == MONO_CALL_VARARG) {
1533 size = 4;
1534 align = 4;
1536 /* Allocate a local slot to hold the sig cookie address */
1537 offset += align - 1;
1538 offset &= ~(align - 1);
1539 cfg->sig_cookie = offset;
1540 offset += size;
1543 offset += SIZEOF_REGISTER - 1;
1544 offset &= ~(SIZEOF_REGISTER - 1);
1546 /* Space for saved registers */
1547 cfg->arch.iregs_offset = offset;
1548 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
1549 if (iregs_to_save) {
1550 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
1551 if (iregs_to_save & (1 << i)) {
1552 offset += SIZEOF_REGISTER;
1557 /* saved float registers */
1558 #if SAVE_FP_REGS
1559 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
1560 if (fregs_to_restore) {
1561 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
1562 if (fregs_to_restore & (1 << i)) {
1563 offset += sizeof(double);
1567 #endif
1569 #if _MIPS_SIM == _ABIO32
1570 /* Now add space for saving the ra */
1571 offset += SIZEOF_VOID_P;
1573 /* change sign? */
1574 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1575 cfg->stack_offset = offset;
1576 cfg->arch.local_alloc_offset = cfg->stack_offset;
1577 #endif
1580 * Now allocate stack slots for the int arg regs (a0 - a3)
1581 * On MIPS o32, these are just above the incoming stack pointer
1582 * Even if the arg has been assigned to a regvar, it gets a stack slot
1585 /* Return struct-by-value results in a hidden first argument */
1586 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1587 cfg->vret_addr->opcode = OP_REGOFFSET;
1588 cfg->vret_addr->inst_c0 = mips_a0;
1589 cfg->vret_addr->inst_offset = offset;
1590 cfg->vret_addr->inst_basereg = frame_reg;
1591 offset += SIZEOF_REGISTER;
1594 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
1595 inst = cfg->args [i];
1596 if (inst->opcode != OP_REGVAR) {
1597 MonoType *arg_type;
1599 if (sig->hasthis && (i == 0))
1600 arg_type = &mono_defaults.object_class->byval_arg;
1601 else
1602 arg_type = sig->params [i - sig->hasthis];
1604 inst->opcode = OP_REGOFFSET;
1605 size = mono_type_size (arg_type, &align);
1607 if (size < SIZEOF_REGISTER) {
1608 size = SIZEOF_REGISTER;
1609 align = SIZEOF_REGISTER;
1611 inst->inst_basereg = frame_reg;
1612 offset = (offset + align - 1) & ~(align - 1);
1613 inst->inst_offset = offset;
1614 offset += size;
1615 if (cfg->verbose_level > 1)
1616 printf ("allocating param %d to fp[%d]\n", i, inst->inst_offset);
1618 else {
1619 #if _MIPS_SIM == _ABIO32
1620 /* o32: Even a0-a3 get stack slots */
1621 size = SIZEOF_REGISTER;
1622 align = SIZEOF_REGISTER;
1623 inst->inst_basereg = frame_reg;
1624 offset = (offset + align - 1) & ~(align - 1);
1625 inst->inst_offset = offset;
1626 offset += size;
1627 if (cfg->verbose_level > 1)
1628 printf ("allocating param %d to fp[%d]\n", i, inst->inst_offset);
1629 #endif
1632 #if _MIPS_SIM == _ABIN32
1633 /* Now add space for saving the ra */
1634 offset += SIZEOF_VOID_P;
1636 /* change sign? */
1637 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1638 cfg->stack_offset = offset;
1639 cfg->arch.local_alloc_offset = cfg->stack_offset;
1640 #endif
1643 void
1644 mono_arch_create_vars (MonoCompile *cfg)
1646 MonoMethodSignature *sig;
1648 sig = mono_method_signature (cfg->method);
1650 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1651 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1652 if (G_UNLIKELY (cfg->verbose_level > 1)) {
1653 printf ("vret_addr = ");
1654 mono_print_ins (cfg->vret_addr);
1659 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1660 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1664 * take the arguments and generate the arch-specific
1665 * instructions to properly call the function in call.
1666 * This includes pushing, moving arguments to the right register
1667 * etc.
1668 * Issue: who does the spilling if needed, and when?
1670 static void
1671 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1673 MonoMethodSignature *tmp_sig;
1674 MonoInst *sig_arg;
1676 if (call->tail_call)
1677 NOT_IMPLEMENTED;
1679 /* FIXME: Add support for signature tokens to AOT */
1680 cfg->disable_aot = TRUE;
1683 * mono_ArgIterator_Setup assumes the signature cookie is
1684 * passed first and all the arguments which were before it are
1685 * passed on the stack after the signature. So compensate by
1686 * passing a different signature.
1688 tmp_sig = mono_metadata_signature_dup (call->signature);
1689 tmp_sig->param_count -= call->signature->sentinelpos;
1690 tmp_sig->sentinelpos = 0;
1691 memcpy (tmp_sig->params, call->signature->params + call->signature->sentinelpos, tmp_sig->param_count * sizeof (MonoType*));
1693 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
1694 sig_arg->dreg = mono_alloc_ireg (cfg);
1695 sig_arg->inst_p0 = tmp_sig;
1696 MONO_ADD_INS (cfg->cbb, sig_arg);
1698 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_sp, cinfo->sig_cookie.offset, sig_arg->dreg);
1701 void
1702 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1704 MonoInst *in, *ins;
1705 MonoMethodSignature *sig;
1706 int i, n;
1707 CallInfo *cinfo;
1708 int is_virtual = 0;
1710 sig = call->signature;
1711 n = sig->param_count + sig->hasthis;
1713 cinfo = get_call_info (cfg->mempool, sig);
1714 if (cinfo->struct_ret)
1715 call->used_iregs |= 1 << cinfo->struct_ret;
1717 for (i = 0; i < n; ++i) {
1718 ArgInfo *ainfo = cinfo->args + i;
1719 MonoType *t;
1721 if (i >= sig->hasthis)
1722 t = sig->params [i - sig->hasthis];
1723 else
1724 t = &mono_defaults.int_class->byval_arg;
1725 t = mini_get_underlying_type (t);
1727 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1728 /* Emit the signature cookie just before the implicit arguments */
1729 emit_sig_cookie (cfg, call, cinfo);
1732 if (is_virtual && i == 0) {
1733 /* the argument will be attached to the call instrucion */
1734 in = call->args [i];
1735 call->used_iregs |= 1 << ainfo->reg;
1736 continue;
1738 in = call->args [i];
1739 if (ainfo->storage == ArgInIReg) {
1740 #if SIZEOF_REGISTER == 4
1741 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1742 MONO_INST_NEW (cfg, ins, OP_MOVE);
1743 ins->dreg = mono_alloc_ireg (cfg);
1744 ins->sreg1 = MONO_LVREG_LS (in->dreg);
1745 MONO_ADD_INS (cfg->cbb, ins);
1746 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + ls_word_idx, FALSE);
1748 MONO_INST_NEW (cfg, ins, OP_MOVE);
1749 ins->dreg = mono_alloc_ireg (cfg);
1750 ins->sreg1 = MONO_LVREG_MS (in->dreg);
1751 MONO_ADD_INS (cfg->cbb, ins);
1752 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + ms_word_idx, FALSE);
1753 } else
1754 #endif
1755 if (!t->byref && (t->type == MONO_TYPE_R4)) {
1756 int freg;
1758 #if PROMOTE_R4_TO_R8
1759 /* ??? - convert to single first? */
1760 MONO_INST_NEW (cfg, ins, OP_MIPS_CVTSD);
1761 ins->dreg = mono_alloc_freg (cfg);
1762 ins->sreg1 = in->dreg;
1763 MONO_ADD_INS (cfg->cbb, ins);
1764 freg = ins->dreg;
1765 #else
1766 freg = in->dreg;
1767 #endif
1768 /* trying to load float value into int registers */
1769 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1S);
1770 ins->dreg = mono_alloc_ireg (cfg);
1771 ins->sreg1 = freg;
1772 MONO_ADD_INS (cfg->cbb, ins);
1773 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1774 } else if (!t->byref && (t->type == MONO_TYPE_R8)) {
1775 /* trying to load float value into int registers */
1776 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1D);
1777 ins->dreg = mono_alloc_ireg (cfg);
1778 ins->sreg1 = in->dreg;
1779 MONO_ADD_INS (cfg->cbb, ins);
1780 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1781 } else {
1782 MONO_INST_NEW (cfg, ins, OP_MOVE);
1783 ins->dreg = mono_alloc_ireg (cfg);
1784 ins->sreg1 = in->dreg;
1785 MONO_ADD_INS (cfg->cbb, ins);
1786 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1788 } else if (ainfo->storage == ArgStructByAddr) {
1789 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1790 ins->opcode = OP_OUTARG_VT;
1791 ins->sreg1 = in->dreg;
1792 ins->klass = in->klass;
1793 ins->inst_p0 = call;
1794 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1795 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1796 MONO_ADD_INS (cfg->cbb, ins);
1797 } else if (ainfo->storage == ArgStructByVal) {
1798 /* this is further handled in mono_arch_emit_outarg_vt () */
1799 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1800 ins->opcode = OP_OUTARG_VT;
1801 ins->sreg1 = in->dreg;
1802 ins->klass = in->klass;
1803 ins->inst_p0 = call;
1804 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1805 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1806 MONO_ADD_INS (cfg->cbb, ins);
1807 } else if (ainfo->storage == ArgOnStack) {
1808 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1809 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1810 } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1811 if (t->type == MONO_TYPE_R8)
1812 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1813 else
1814 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1815 } else {
1816 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1818 } else if (ainfo->storage == ArgInFReg) {
1819 if (t->type == MONO_TYPE_VALUETYPE) {
1820 /* this is further handled in mono_arch_emit_outarg_vt () */
1821 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1822 ins->opcode = OP_OUTARG_VT;
1823 ins->sreg1 = in->dreg;
1824 ins->klass = in->klass;
1825 ins->inst_p0 = call;
1826 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1827 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1828 MONO_ADD_INS (cfg->cbb, ins);
1830 cfg->flags |= MONO_CFG_HAS_FPOUT;
1831 } else {
1832 int dreg = mono_alloc_freg (cfg);
1834 if (ainfo->size == 4) {
1835 MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, dreg, in->dreg);
1836 } else {
1837 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1838 ins->dreg = dreg;
1839 ins->sreg1 = in->dreg;
1840 MONO_ADD_INS (cfg->cbb, ins);
1843 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1844 cfg->flags |= MONO_CFG_HAS_FPOUT;
1846 } else {
1847 g_assert_not_reached ();
1851 /* Handle the case where there are no implicit arguments */
1852 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1853 emit_sig_cookie (cfg, call, cinfo);
1855 if (cinfo->struct_ret) {
1856 MonoInst *vtarg;
1858 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1859 vtarg->sreg1 = call->vret_var->dreg;
1860 vtarg->dreg = mono_alloc_preg (cfg);
1861 MONO_ADD_INS (cfg->cbb, vtarg);
1863 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1865 #if 0
1867 * Reverse the call->out_args list.
1870 MonoInst *prev = NULL, *list = call->out_args, *next;
1871 while (list) {
1872 next = list->next;
1873 list->next = prev;
1874 prev = list;
1875 list = next;
1877 call->out_args = prev;
1879 #endif
1880 call->stack_usage = cinfo->stack_usage;
1881 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1882 #if _MIPS_SIM == _ABIO32
1883 /* a0-a3 always present */
1884 cfg->param_area = MAX (cfg->param_area, 4 * SIZEOF_REGISTER);
1885 #endif
1886 cfg->param_area = (cfg->param_area + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1887 cfg->flags |= MONO_CFG_HAS_CALLS;
1889 * should set more info in call, such as the stack space
1890 * used by the args that needs to be added back to esp
1894 void
1895 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1897 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1898 ArgInfo *ainfo = ins->inst_p1;
1899 int ovf_size = ainfo->vtsize;
1900 int doffset = ainfo->offset;
1901 int i, soffset, dreg;
1903 if (ainfo->storage == ArgStructByVal) {
1904 #if 0
1905 if (cfg->verbose_level > 0) {
1906 char* nm = mono_method_full_name (cfg->method, TRUE);
1907 g_print ("Method %s outarg_vt struct doffset=%d ainfo->size=%d ovf_size=%d\n",
1908 nm, doffset, ainfo->size, ovf_size);
1909 g_free (nm);
1911 #endif
1913 soffset = 0;
1914 for (i = 0; i < ainfo->size; ++i) {
1915 dreg = mono_alloc_ireg (cfg);
1916 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1917 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1918 soffset += SIZEOF_REGISTER;
1920 if (ovf_size != 0) {
1921 mini_emit_memcpy (cfg, mips_sp, doffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
1923 } else if (ainfo->storage == ArgInFReg) {
1924 int tmpr = mono_alloc_freg (cfg);
1926 if (ainfo->size == 4)
1927 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1928 else
1929 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1930 dreg = mono_alloc_freg (cfg);
1931 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1932 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1933 } else {
1934 MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
1935 MonoInst *load;
1936 guint32 size;
1938 /* FIXME: alignment? */
1939 if (call->signature->pinvoke) {
1940 size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
1941 vtcopy->backend.is_pinvoke = 1;
1942 } else {
1943 size = mini_type_stack_size (&src->klass->byval_arg, NULL);
1945 if (size > 0)
1946 g_assert (ovf_size > 0);
1948 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1949 mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, size, 0);
1951 if (ainfo->offset)
1952 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_at, ainfo->offset, load->dreg);
1953 else
1954 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1958 void
1959 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1961 MonoType *ret = mini_get_underlying_type (mono_method_signature (method)->ret);
1963 if (!ret->byref) {
1964 #if (SIZEOF_REGISTER == 4)
1965 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1966 MonoInst *ins;
1968 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1969 ins->sreg1 = MONO_LVREG_LS (val->dreg);
1970 ins->sreg2 = MONO_LVREG_MS (val->dreg);
1971 MONO_ADD_INS (cfg->cbb, ins);
1972 return;
1974 #endif
1975 if (ret->type == MONO_TYPE_R8) {
1976 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1977 return;
1979 if (ret->type == MONO_TYPE_R4) {
1980 MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, cfg->ret->dreg, val->dreg);
1981 return;
1984 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1987 void
1988 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1990 MonoInst *ins, *n, *last_ins = NULL;
1992 if (cfg->verbose_level > 2)
1993 g_print ("Basic block %d peephole pass 1\n", bb->block_num);
1995 ins = bb->code;
1996 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1997 if (cfg->verbose_level > 2)
1998 mono_print_ins_index (0, ins);
2000 switch (ins->opcode) {
2001 #if 0
2002 case OP_LOAD_MEMBASE:
2003 case OP_LOADI4_MEMBASE:
2005 * OP_IADD reg2, reg1, const1
2006 * OP_LOAD_MEMBASE const2(reg2), reg3
2007 * ->
2008 * OP_LOAD_MEMBASE (const1+const2)(reg1), reg3
2010 if (last_ins && (last_ins->opcode == OP_IADD_IMM || last_ins->opcode == OP_ADD_IMM) && (last_ins->dreg == ins->inst_basereg) && (last_ins->sreg1 != last_ins->dreg)){
2011 int const1 = last_ins->inst_imm;
2012 int const2 = ins->inst_offset;
2014 if (mips_is_imm16 (const1 + const2)) {
2015 ins->inst_basereg = last_ins->sreg1;
2016 ins->inst_offset = const1 + const2;
2019 break;
2020 #endif
2023 last_ins = ins;
2024 ins = ins->next;
2026 bb->last_ins = last_ins;
2029 void
2030 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
2032 MonoInst *ins, *n, *last_ins = NULL;
2033 ins = bb->code;
2035 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
2036 MonoInst *last_ins = ins->prev;
2038 switch (ins->opcode) {
2039 case OP_MUL_IMM:
2040 /* remove unnecessary multiplication with 1 */
2041 if (ins->inst_imm == 1) {
2042 if (ins->dreg != ins->sreg1) {
2043 ins->opcode = OP_MOVE;
2044 } else {
2045 MONO_DELETE_INS (bb, ins);
2046 continue;
2048 } else {
2049 int power2 = mono_is_power_of_two (ins->inst_imm);
2050 if (power2 > 0) {
2051 ins->opcode = OP_SHL_IMM;
2052 ins->inst_imm = power2;
2055 break;
2056 case OP_LOAD_MEMBASE:
2057 case OP_LOADI4_MEMBASE:
2059 * OP_STORE_MEMBASE_REG reg, offset(basereg)
2060 * OP_LOAD_MEMBASE offset(basereg), reg
2062 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
2063 || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
2064 ins->inst_basereg == last_ins->inst_destbasereg &&
2065 ins->inst_offset == last_ins->inst_offset) {
2066 if (ins->dreg == last_ins->sreg1) {
2067 MONO_DELETE_INS (bb, ins);
2068 continue;
2069 } else {
2070 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2071 ins->opcode = OP_MOVE;
2072 ins->sreg1 = last_ins->sreg1;
2074 break;
2077 * Note: reg1 must be different from the basereg in the second load
2078 * OP_LOAD_MEMBASE offset(basereg), reg1
2079 * OP_LOAD_MEMBASE offset(basereg), reg2
2080 * -->
2081 * OP_LOAD_MEMBASE offset(basereg), reg1
2082 * OP_MOVE reg1, reg2
2084 if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
2085 || last_ins->opcode == OP_LOAD_MEMBASE) &&
2086 ins->inst_basereg != last_ins->dreg &&
2087 ins->inst_basereg == last_ins->inst_basereg &&
2088 ins->inst_offset == last_ins->inst_offset) {
2090 if (ins->dreg == last_ins->dreg) {
2091 MONO_DELETE_INS (bb, ins);
2092 continue;
2093 } else {
2094 ins->opcode = OP_MOVE;
2095 ins->sreg1 = last_ins->dreg;
2098 //g_assert_not_reached ();
2099 break;
2101 #if 0
2103 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2104 * OP_LOAD_MEMBASE offset(basereg), reg
2105 * -->
2106 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2107 * OP_ICONST reg, imm
2109 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
2110 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
2111 ins->inst_basereg == last_ins->inst_destbasereg &&
2112 ins->inst_offset == last_ins->inst_offset) {
2113 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2114 ins->opcode = OP_ICONST;
2115 ins->inst_c0 = last_ins->inst_imm;
2116 g_assert_not_reached (); // check this rule
2117 break;
2119 #endif
2120 break;
2121 case OP_LOADU1_MEMBASE:
2122 case OP_LOADI1_MEMBASE:
2123 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
2124 ins->inst_basereg == last_ins->inst_destbasereg &&
2125 ins->inst_offset == last_ins->inst_offset) {
2126 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
2127 ins->sreg1 = last_ins->sreg1;
2129 break;
2130 case OP_LOADU2_MEMBASE:
2131 case OP_LOADI2_MEMBASE:
2132 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
2133 ins->inst_basereg == last_ins->inst_destbasereg &&
2134 ins->inst_offset == last_ins->inst_offset) {
2135 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
2136 ins->sreg1 = last_ins->sreg1;
2138 break;
2139 case OP_ICONV_TO_I4:
2140 case OP_ICONV_TO_U4:
2141 case OP_MOVE:
2142 ins->opcode = OP_MOVE;
2144 * OP_MOVE reg, reg
2146 if (ins->dreg == ins->sreg1) {
2147 MONO_DELETE_INS (bb, ins);
2148 continue;
2151 * OP_MOVE sreg, dreg
2152 * OP_MOVE dreg, sreg
2154 if (last_ins && last_ins->opcode == OP_MOVE &&
2155 ins->sreg1 == last_ins->dreg &&
2156 ins->dreg == last_ins->sreg1) {
2157 MONO_DELETE_INS (bb, ins);
2158 continue;
2160 break;
2162 last_ins = ins;
2163 ins = ins->next;
2165 bb->last_ins = last_ins;
2168 void
2169 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins)
2171 int tmp1 = -1;
2172 int tmp2 = -1;
2173 int tmp3 = -1;
2174 int tmp4 = -1;
2175 int tmp5 = -1;
2177 switch (ins->opcode) {
2178 case OP_LADD:
2179 tmp1 = mono_alloc_ireg (cfg);
2180 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2181 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2182 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2183 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
2184 NULLIFY_INS(ins);
2185 break;
2187 case OP_LADD_IMM:
2188 tmp1 = mono_alloc_ireg (cfg);
2189 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
2190 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2191 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
2192 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
2193 NULLIFY_INS(ins);
2194 break;
2196 case OP_LSUB:
2197 tmp1 = mono_alloc_ireg (cfg);
2198 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2199 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2200 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2201 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2202 NULLIFY_INS(ins);
2203 break;
2205 case OP_LSUB_IMM:
2206 tmp1 = mono_alloc_ireg (cfg);
2207 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
2208 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2209 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
2210 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2211 NULLIFY_INS(ins);
2212 break;
2214 case OP_LNEG:
2215 tmp1 = mono_alloc_ireg (cfg);
2216 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, mips_zero, ins->sreg1+1);
2217 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, mips_zero, ins->dreg+1);
2218 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, mips_zero, ins->sreg1+2);
2219 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2220 NULLIFY_INS(ins);
2221 break;
2223 case OP_LADD_OVF:
2224 tmp1 = mono_alloc_ireg (cfg);
2225 tmp2 = mono_alloc_ireg (cfg);
2226 tmp3 = mono_alloc_ireg (cfg);
2227 tmp4 = mono_alloc_ireg (cfg);
2228 tmp5 = mono_alloc_ireg (cfg);
2230 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2232 /* tmp1 holds the carry from the low 32-bit to the high 32-bits */
2233 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->dreg+1, ins->sreg1+1);
2235 /* add the high 32-bits, and add in the carry from the low 32-bits */
2236 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2237 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp5, ins->dreg+2);
2239 /* Overflow happens if
2240 * neg + neg = pos or
2241 * pos + pos = neg
2242 * XOR of the high bits returns 0 if the signs match
2243 * XOR of that with the high bit of the result return 1 if overflow.
2246 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2247 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2249 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2250 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg+2, ins->sreg2+2);
2251 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp2, tmp2);
2253 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2254 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp3, tmp2, tmp1);
2255 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2257 /* Now, if (tmp4 == 0) then overflow */
2258 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp4, mips_zero, "OverflowException");
2259 NULLIFY_INS(ins);
2260 break;
2262 case OP_LADD_OVF_UN:
2263 tmp1 = mono_alloc_ireg (cfg);
2264 tmp2 = mono_alloc_ireg (cfg);
2266 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2267 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2268 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2269 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp1, ins->dreg+2);
2270 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->dreg+2, ins->sreg1+2);
2271 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2272 NULLIFY_INS(ins);
2273 break;
2275 case OP_LSUB_OVF:
2276 tmp1 = mono_alloc_ireg (cfg);
2277 tmp2 = mono_alloc_ireg (cfg);
2278 tmp3 = mono_alloc_ireg (cfg);
2279 tmp4 = mono_alloc_ireg (cfg);
2280 tmp5 = mono_alloc_ireg (cfg);
2282 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2284 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->sreg1+1, ins->dreg+1);
2285 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2286 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp5);
2288 /* Overflow happens if
2289 * neg - pos = pos or
2290 * pos - neg = neg
2291 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2293 * tmp1 = (lhs ^ rhs)
2294 * tmp2 = (lhs ^ result)
2295 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2298 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2299 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1+2, ins->dreg+2);
2300 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp3, tmp2, tmp1);
2301 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2303 /* Now, if (tmp4 == 1) then overflow */
2304 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp4, mips_zero, "OverflowException");
2305 NULLIFY_INS(ins);
2306 break;
2308 case OP_LSUB_OVF_UN:
2309 tmp1 = mono_alloc_ireg (cfg);
2310 tmp2 = mono_alloc_ireg (cfg);
2312 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2313 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2314 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2315 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2317 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->sreg1+2, ins->dreg+2);
2318 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2319 NULLIFY_INS(ins);
2320 break;
2321 case OP_LCONV_TO_OVF_I4_2:
2322 tmp1 = mono_alloc_ireg (cfg);
2324 /* Overflows if reg2 != sign extension of reg1 */
2325 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp1, ins->sreg1, 31);
2326 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, ins->sreg2, tmp1, "OverflowException");
2327 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
2328 NULLIFY_INS(ins);
2329 break;
2330 default:
2331 break;
2335 void
2336 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
2338 int tmp1 = -1;
2339 int tmp2 = -1;
2340 int tmp3 = -1;
2341 int tmp4 = -1;
2342 int tmp5 = -1;
2344 switch (ins->opcode) {
2345 case OP_IADD_OVF:
2346 tmp1 = mono_alloc_ireg (cfg);
2347 tmp2 = mono_alloc_ireg (cfg);
2348 tmp3 = mono_alloc_ireg (cfg);
2349 tmp4 = mono_alloc_ireg (cfg);
2350 tmp5 = mono_alloc_ireg (cfg);
2352 /* add the operands */
2354 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2356 /* Overflow happens if
2357 * neg + neg = pos or
2358 * pos + pos = neg
2360 * (bit31s of operands match) AND (bit31 of operand != bit31 of result)
2361 * XOR of the high bit returns 0 if the signs match
2362 * XOR of that with the high bit of the result return 1 if overflow.
2365 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2366 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2368 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2369 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg, ins->sreg2);
2370 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp3, tmp2);
2372 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2373 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp4, tmp3, tmp1);
2375 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp5, tmp4, 31);
2377 /* Now, if (tmp5 == 0) then overflow */
2378 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp5, mips_zero, "OverflowException");
2379 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2380 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2381 NULLIFY_INS(ins);
2382 break;
2384 case OP_IADD_OVF_UN:
2385 tmp1 = mono_alloc_ireg (cfg);
2387 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2388 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg, ins->sreg1);
2389 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2390 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2391 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2392 NULLIFY_INS(ins);
2393 break;
2395 case OP_ISUB_OVF:
2396 tmp1 = mono_alloc_ireg (cfg);
2397 tmp2 = mono_alloc_ireg (cfg);
2398 tmp3 = mono_alloc_ireg (cfg);
2399 tmp4 = mono_alloc_ireg (cfg);
2400 tmp5 = mono_alloc_ireg (cfg);
2402 /* add the operands */
2404 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2406 /* Overflow happens if
2407 * neg - pos = pos or
2408 * pos - neg = neg
2409 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2411 * tmp1 = (lhs ^ rhs)
2412 * tmp2 = (lhs ^ result)
2413 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2416 /* tmp3 = 1 if the signs of the two inputs differ */
2417 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2418 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1, ins->dreg);
2419 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp3, tmp1, 0);
2420 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp4, tmp2, 0);
2421 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp5, tmp4, tmp3);
2423 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp5, mips_zero, "OverflowException");
2424 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2425 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2426 NULLIFY_INS(ins);
2427 break;
2429 case OP_ISUB_OVF_UN:
2430 tmp1 = mono_alloc_ireg (cfg);
2432 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2433 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1, ins->dreg);
2434 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2435 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2436 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2437 NULLIFY_INS(ins);
2438 break;
2442 static int
2443 map_to_reg_reg_op (int op)
2445 switch (op) {
2446 case OP_ADD_IMM:
2447 return OP_IADD;
2448 case OP_SUB_IMM:
2449 return OP_ISUB;
2450 case OP_AND_IMM:
2451 return OP_IAND;
2452 case OP_COMPARE_IMM:
2453 return OP_COMPARE;
2454 case OP_ICOMPARE_IMM:
2455 return OP_ICOMPARE;
2456 case OP_LCOMPARE_IMM:
2457 return OP_LCOMPARE;
2458 case OP_ADDCC_IMM:
2459 return OP_IADDCC;
2460 case OP_ADC_IMM:
2461 return OP_IADC;
2462 case OP_SUBCC_IMM:
2463 return OP_ISUBCC;
2464 case OP_SBB_IMM:
2465 return OP_ISBB;
2466 case OP_OR_IMM:
2467 return OP_IOR;
2468 case OP_XOR_IMM:
2469 return OP_IXOR;
2470 case OP_MUL_IMM:
2471 return OP_IMUL;
2472 case OP_LOAD_MEMBASE:
2473 return OP_LOAD_MEMINDEX;
2474 case OP_LOADI4_MEMBASE:
2475 return OP_LOADI4_MEMINDEX;
2476 case OP_LOADU4_MEMBASE:
2477 return OP_LOADU4_MEMINDEX;
2478 case OP_LOADU1_MEMBASE:
2479 return OP_LOADU1_MEMINDEX;
2480 case OP_LOADI2_MEMBASE:
2481 return OP_LOADI2_MEMINDEX;
2482 case OP_LOADU2_MEMBASE:
2483 return OP_LOADU2_MEMINDEX;
2484 case OP_LOADI1_MEMBASE:
2485 return OP_LOADI1_MEMINDEX;
2486 case OP_LOADR4_MEMBASE:
2487 return OP_LOADR4_MEMINDEX;
2488 case OP_LOADR8_MEMBASE:
2489 return OP_LOADR8_MEMINDEX;
2490 case OP_STOREI1_MEMBASE_REG:
2491 return OP_STOREI1_MEMINDEX;
2492 case OP_STOREI2_MEMBASE_REG:
2493 return OP_STOREI2_MEMINDEX;
2494 case OP_STOREI4_MEMBASE_REG:
2495 return OP_STOREI4_MEMINDEX;
2496 case OP_STORE_MEMBASE_REG:
2497 return OP_STORE_MEMINDEX;
2498 case OP_STORER4_MEMBASE_REG:
2499 return OP_STORER4_MEMINDEX;
2500 case OP_STORER8_MEMBASE_REG:
2501 return OP_STORER8_MEMINDEX;
2502 case OP_STORE_MEMBASE_IMM:
2503 return OP_STORE_MEMBASE_REG;
2504 case OP_STOREI1_MEMBASE_IMM:
2505 return OP_STOREI1_MEMBASE_REG;
2506 case OP_STOREI2_MEMBASE_IMM:
2507 return OP_STOREI2_MEMBASE_REG;
2508 case OP_STOREI4_MEMBASE_IMM:
2509 return OP_STOREI4_MEMBASE_REG;
2510 case OP_STOREI8_MEMBASE_IMM:
2511 return OP_STOREI8_MEMBASE_REG;
2513 if (mono_op_imm_to_op (op) == -1)
2514 g_error ("mono_op_imm_to_op failed for %s\n", mono_inst_name (op));
2515 return mono_op_imm_to_op (op);
2518 static int
2519 map_to_mips_op (int op)
2521 switch (op) {
2522 case OP_FBEQ:
2523 return OP_MIPS_FBEQ;
2524 case OP_FBGE:
2525 return OP_MIPS_FBGE;
2526 case OP_FBGT:
2527 return OP_MIPS_FBGT;
2528 case OP_FBLE:
2529 return OP_MIPS_FBLE;
2530 case OP_FBLT:
2531 return OP_MIPS_FBLT;
2532 case OP_FBNE_UN:
2533 return OP_MIPS_FBNE;
2534 case OP_FBGE_UN:
2535 return OP_MIPS_FBGE_UN;
2536 case OP_FBGT_UN:
2537 return OP_MIPS_FBGT_UN;
2538 case OP_FBLE_UN:
2539 return OP_MIPS_FBLE_UN;
2540 case OP_FBLT_UN:
2541 return OP_MIPS_FBLT_UN;
2543 case OP_FCEQ:
2544 case OP_FCGT:
2545 case OP_FCGT_UN:
2546 case OP_FCLT:
2547 case OP_FCLT_UN:
2548 default:
2549 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (op), __FUNCTION__);
2550 g_assert_not_reached ();
2554 #define NEW_INS(cfg,after,dest,op) do { \
2555 MONO_INST_NEW((cfg), (dest), (op)); \
2556 mono_bblock_insert_after_ins (bb, (after), (dest)); \
2557 } while (0)
2559 #define INS(pos,op,_dreg,_sreg1,_sreg2) do { \
2560 MonoInst *temp; \
2561 MONO_INST_NEW(cfg, temp, (op)); \
2562 mono_bblock_insert_after_ins (bb, (pos), temp); \
2563 temp->dreg = (_dreg); \
2564 temp->sreg1 = (_sreg1); \
2565 temp->sreg2 = (_sreg2); \
2566 pos = temp; \
2567 } while (0)
2569 #define INS_IMM(pos,op,_dreg,_sreg1,_imm) do { \
2570 MonoInst *temp; \
2571 MONO_INST_NEW(cfg, temp, (op)); \
2572 mono_bblock_insert_after_ins (bb, (pos), temp); \
2573 temp->dreg = (_dreg); \
2574 temp->sreg1 = (_sreg1); \
2575 temp->inst_c0 = (_imm); \
2576 pos = temp; \
2577 } while (0)
2580 * Remove from the instruction list the instructions that can't be
2581 * represented with very simple instructions with no register
2582 * requirements.
2584 void
2585 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2587 MonoInst *ins, *next, *temp, *last_ins = NULL;
2588 int imm;
2590 #if 1
2591 if (cfg->verbose_level > 2) {
2592 int idx = 0;
2594 g_print ("BASIC BLOCK %d (before lowering)\n", bb->block_num);
2595 MONO_BB_FOR_EACH_INS (bb, ins) {
2596 mono_print_ins_index (idx++, ins);
2600 #endif
2602 MONO_BB_FOR_EACH_INS (bb, ins) {
2603 loop_start:
2604 switch (ins->opcode) {
2605 case OP_COMPARE:
2606 case OP_ICOMPARE:
2607 case OP_LCOMPARE:
2608 next = ins->next;
2609 /* Branch opts can eliminate the branch */
2610 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2611 NULLIFY_INS(ins);
2612 break;
2614 break;
2616 case OP_COMPARE_IMM:
2617 case OP_ICOMPARE_IMM:
2618 case OP_LCOMPARE_IMM:
2619 next = ins->next;
2620 /* Branch opts can eliminate the branch */
2621 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2622 NULLIFY_INS(ins);
2623 break;
2625 if (ins->inst_imm) {
2626 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2627 temp->inst_c0 = ins->inst_imm;
2628 temp->dreg = mono_alloc_ireg (cfg);
2629 ins->sreg2 = temp->dreg;
2630 last_ins = temp;
2632 else {
2633 ins->sreg2 = mips_zero;
2635 if (ins->opcode == OP_COMPARE_IMM)
2636 ins->opcode = OP_COMPARE;
2637 else if (ins->opcode == OP_ICOMPARE_IMM)
2638 ins->opcode = OP_ICOMPARE;
2639 else if (ins->opcode == OP_LCOMPARE_IMM)
2640 ins->opcode = OP_LCOMPARE;
2641 goto loop_start;
2643 case OP_IDIV_UN_IMM:
2644 case OP_IDIV_IMM:
2645 case OP_IREM_IMM:
2646 case OP_IREM_UN_IMM:
2647 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2648 temp->inst_c0 = ins->inst_imm;
2649 temp->dreg = mono_alloc_ireg (cfg);
2650 ins->sreg2 = temp->dreg;
2651 if (ins->opcode == OP_IDIV_IMM)
2652 ins->opcode = OP_IDIV;
2653 else if (ins->opcode == OP_IREM_IMM)
2654 ins->opcode = OP_IREM;
2655 else if (ins->opcode == OP_IDIV_UN_IMM)
2656 ins->opcode = OP_IDIV_UN;
2657 else if (ins->opcode == OP_IREM_UN_IMM)
2658 ins->opcode = OP_IREM_UN;
2659 last_ins = temp;
2660 /* handle rem separately */
2661 goto loop_start;
2663 #if 0
2664 case OP_AND_IMM:
2665 case OP_OR_IMM:
2666 case OP_XOR_IMM:
2667 if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
2668 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2669 temp->inst_c0 = ins->inst_imm;
2670 temp->dreg = mono_alloc_ireg (cfg);
2671 ins->sreg2 = temp->dreg;
2672 ins->opcode = map_to_reg_reg_op (ins->opcode);
2674 break;
2675 #endif
2676 case OP_AND_IMM:
2677 case OP_IAND_IMM:
2678 case OP_OR_IMM:
2679 case OP_IOR_IMM:
2680 case OP_XOR_IMM:
2681 case OP_IXOR_IMM:
2682 /* unsigned 16 bit immediate */
2683 if (ins->inst_imm & 0xffff0000) {
2684 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2685 temp->inst_c0 = ins->inst_imm;
2686 temp->dreg = mono_alloc_ireg (cfg);
2687 ins->sreg2 = temp->dreg;
2688 ins->opcode = map_to_reg_reg_op (ins->opcode);
2690 break;
2692 case OP_IADD_IMM:
2693 case OP_ADD_IMM:
2694 case OP_ADDCC_IMM:
2695 /* signed 16 bit immediate */
2696 if (!mips_is_imm16 (ins->inst_imm)) {
2697 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2698 temp->inst_c0 = ins->inst_imm;
2699 temp->dreg = mono_alloc_ireg (cfg);
2700 ins->sreg2 = temp->dreg;
2701 ins->opcode = map_to_reg_reg_op (ins->opcode);
2703 break;
2705 case OP_SUB_IMM:
2706 case OP_ISUB_IMM:
2707 if (!mips_is_imm16 (-ins->inst_imm)) {
2708 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2709 temp->inst_c0 = ins->inst_imm;
2710 temp->dreg = mono_alloc_ireg (cfg);
2711 ins->sreg2 = temp->dreg;
2712 ins->opcode = map_to_reg_reg_op (ins->opcode);
2714 break;
2716 case OP_MUL_IMM:
2717 case OP_IMUL_IMM:
2718 if (ins->inst_imm == 1) {
2719 ins->opcode = OP_MOVE;
2720 break;
2722 if (ins->inst_imm == 0) {
2723 ins->opcode = OP_ICONST;
2724 ins->inst_c0 = 0;
2725 break;
2727 imm = mono_is_power_of_two (ins->inst_imm);
2728 if (imm > 0) {
2729 ins->opcode = OP_SHL_IMM;
2730 ins->inst_imm = imm;
2731 break;
2733 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2734 temp->inst_c0 = ins->inst_imm;
2735 temp->dreg = mono_alloc_ireg (cfg);
2736 ins->sreg2 = temp->dreg;
2737 ins->opcode = map_to_reg_reg_op (ins->opcode);
2738 break;
2740 case OP_LOCALLOC_IMM:
2741 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2742 temp->inst_c0 = ins->inst_imm;
2743 temp->dreg = mono_alloc_ireg (cfg);
2744 ins->sreg1 = temp->dreg;
2745 ins->opcode = OP_LOCALLOC;
2746 break;
2748 case OP_LOADR4_MEMBASE:
2749 case OP_STORER4_MEMBASE_REG:
2750 /* we can do two things: load the immed in a register
2751 * and use an indexed load, or see if the immed can be
2752 * represented as an ad_imm + a load with a smaller offset
2753 * that fits. We just do the first for now, optimize later.
2755 if (mips_is_imm16 (ins->inst_offset))
2756 break;
2757 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2758 temp->inst_c0 = ins->inst_offset;
2759 temp->dreg = mono_alloc_ireg (cfg);
2760 ins->sreg2 = temp->dreg;
2761 ins->opcode = map_to_reg_reg_op (ins->opcode);
2762 break;
2764 case OP_STORE_MEMBASE_IMM:
2765 case OP_STOREI1_MEMBASE_IMM:
2766 case OP_STOREI2_MEMBASE_IMM:
2767 case OP_STOREI4_MEMBASE_IMM:
2768 case OP_STOREI8_MEMBASE_IMM:
2769 if (!ins->inst_imm) {
2770 ins->sreg1 = mips_zero;
2771 ins->opcode = map_to_reg_reg_op (ins->opcode);
2773 else {
2774 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2775 temp->inst_c0 = ins->inst_imm;
2776 temp->dreg = mono_alloc_ireg (cfg);
2777 ins->sreg1 = temp->dreg;
2778 ins->opcode = map_to_reg_reg_op (ins->opcode);
2779 last_ins = temp;
2780 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2782 break;
2784 case OP_FCOMPARE:
2785 next = ins->next;
2786 /* Branch opts can eliminate the branch */
2787 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2788 NULLIFY_INS(ins);
2789 break;
2791 g_assert(next);
2794 * remap compare/branch and compare/set
2795 * to MIPS specific opcodes.
2797 next->opcode = map_to_mips_op (next->opcode);
2798 next->sreg1 = ins->sreg1;
2799 next->sreg2 = ins->sreg2;
2800 NULLIFY_INS(ins);
2801 break;
2803 #if 0
2804 case OP_R8CONST:
2805 case OP_R4CONST:
2806 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2807 temp->inst_c0 = (guint32)ins->inst_p0;
2808 temp->dreg = mono_alloc_ireg (cfg);
2809 ins->inst_basereg = temp->dreg;
2810 ins->inst_offset = 0;
2811 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2812 last_ins = temp;
2813 /* make it handle the possibly big ins->inst_offset
2814 * later optimize to use lis + load_membase
2816 goto loop_start;
2817 #endif
2818 case OP_IBEQ:
2819 g_assert (ins_is_compare(last_ins));
2820 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->sreg1, last_ins->sreg2);
2821 NULLIFY_INS(last_ins);
2822 break;
2824 case OP_IBNE_UN:
2825 g_assert (ins_is_compare(last_ins));
2826 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->sreg1, last_ins->sreg2);
2827 NULLIFY_INS(last_ins);
2828 break;
2830 case OP_IBGE:
2831 g_assert (ins_is_compare(last_ins));
2832 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2833 last_ins->dreg = mono_alloc_ireg (cfg);
2834 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2835 break;
2837 case OP_IBGE_UN:
2838 g_assert (ins_is_compare(last_ins));
2839 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2840 last_ins->dreg = mono_alloc_ireg (cfg);
2841 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2842 break;
2844 case OP_IBLT:
2845 g_assert (ins_is_compare(last_ins));
2846 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2847 last_ins->dreg = mono_alloc_ireg (cfg);
2848 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2849 break;
2851 case OP_IBLT_UN:
2852 g_assert (ins_is_compare(last_ins));
2853 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2854 last_ins->dreg = mono_alloc_ireg (cfg);
2855 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2856 break;
2858 case OP_IBLE:
2859 g_assert (ins_is_compare(last_ins));
2860 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2861 last_ins->dreg = mono_alloc_ireg (cfg);
2862 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2863 break;
2865 case OP_IBLE_UN:
2866 g_assert (ins_is_compare(last_ins));
2867 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2868 last_ins->dreg = mono_alloc_ireg (cfg);
2869 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2870 break;
2872 case OP_IBGT:
2873 g_assert (ins_is_compare(last_ins));
2874 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2875 last_ins->dreg = mono_alloc_ireg (cfg);
2876 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2877 break;
2879 case OP_IBGT_UN:
2880 g_assert (ins_is_compare(last_ins));
2881 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2882 last_ins->dreg = mono_alloc_ireg (cfg);
2883 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2884 break;
2886 case OP_CEQ:
2887 case OP_ICEQ:
2888 g_assert (ins_is_compare(last_ins));
2889 last_ins->opcode = OP_IXOR;
2890 last_ins->dreg = mono_alloc_ireg(cfg);
2891 INS_REWRITE_IMM(ins, OP_MIPS_SLTIU, last_ins->dreg, 1);
2892 break;
2894 case OP_CLT:
2895 case OP_ICLT:
2896 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2897 NULLIFY_INS(last_ins);
2898 break;
2901 case OP_CLT_UN:
2902 case OP_ICLT_UN:
2903 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2904 NULLIFY_INS(last_ins);
2905 break;
2907 case OP_CGT:
2908 case OP_ICGT:
2909 g_assert (ins_is_compare(last_ins));
2910 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2911 MONO_DELETE_INS(bb, last_ins);
2912 break;
2914 case OP_CGT_UN:
2915 case OP_ICGT_UN:
2916 g_assert (ins_is_compare(last_ins));
2917 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2918 MONO_DELETE_INS(bb, last_ins);
2919 break;
2921 case OP_COND_EXC_EQ:
2922 case OP_COND_EXC_IEQ:
2923 g_assert (ins_is_compare(last_ins));
2924 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, last_ins->sreg1, last_ins->sreg2);
2925 MONO_DELETE_INS(bb, last_ins);
2926 break;
2928 case OP_COND_EXC_GE:
2929 case OP_COND_EXC_IGE:
2930 g_assert (ins_is_compare(last_ins));
2931 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE, last_ins->sreg1, last_ins->sreg2);
2932 MONO_DELETE_INS(bb, last_ins);
2933 break;
2935 case OP_COND_EXC_GT:
2936 case OP_COND_EXC_IGT:
2937 g_assert (ins_is_compare(last_ins));
2938 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT, last_ins->sreg1, last_ins->sreg2);
2939 MONO_DELETE_INS(bb, last_ins);
2940 break;
2942 case OP_COND_EXC_LE:
2943 case OP_COND_EXC_ILE:
2944 g_assert (ins_is_compare(last_ins));
2945 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE, last_ins->sreg1, last_ins->sreg2);
2946 MONO_DELETE_INS(bb, last_ins);
2947 break;
2949 case OP_COND_EXC_LT:
2950 case OP_COND_EXC_ILT:
2951 g_assert (ins_is_compare(last_ins));
2952 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT, last_ins->sreg1, last_ins->sreg2);
2953 MONO_DELETE_INS(bb, last_ins);
2954 break;
2956 case OP_COND_EXC_NE_UN:
2957 case OP_COND_EXC_INE_UN:
2958 g_assert (ins_is_compare(last_ins));
2959 INS_REWRITE(ins, OP_MIPS_COND_EXC_NE_UN, last_ins->sreg1, last_ins->sreg2);
2960 MONO_DELETE_INS(bb, last_ins);
2961 break;
2963 case OP_COND_EXC_GE_UN:
2964 case OP_COND_EXC_IGE_UN:
2965 g_assert (ins_is_compare(last_ins));
2966 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE_UN, last_ins->sreg1, last_ins->sreg2);
2967 MONO_DELETE_INS(bb, last_ins);
2968 break;
2970 case OP_COND_EXC_GT_UN:
2971 case OP_COND_EXC_IGT_UN:
2972 g_assert (ins_is_compare(last_ins));
2973 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT_UN, last_ins->sreg1, last_ins->sreg2);
2974 MONO_DELETE_INS(bb, last_ins);
2975 break;
2977 case OP_COND_EXC_LE_UN:
2978 case OP_COND_EXC_ILE_UN:
2979 g_assert (ins_is_compare(last_ins));
2980 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE_UN, last_ins->sreg1, last_ins->sreg2);
2981 MONO_DELETE_INS(bb, last_ins);
2982 break;
2984 case OP_COND_EXC_LT_UN:
2985 case OP_COND_EXC_ILT_UN:
2986 g_assert (ins_is_compare(last_ins));
2987 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT_UN, last_ins->sreg1, last_ins->sreg2);
2988 MONO_DELETE_INS(bb, last_ins);
2989 break;
2991 case OP_COND_EXC_OV:
2992 case OP_COND_EXC_IOV: {
2993 int tmp1, tmp2, tmp3, tmp4, tmp5;
2994 MonoInst *pos = last_ins;
2996 /* Overflow happens if
2997 * neg + neg = pos or
2998 * pos + pos = neg
3000 * (bit31s of operands match) AND (bit31 of operand
3001 * != bit31 of result)
3002 * XOR of the high bit returns 0 if the signs match
3003 * XOR of that with the high bit of the result return 1
3004 * if overflow.
3006 g_assert (last_ins->opcode == OP_IADC);
3008 tmp1 = mono_alloc_ireg (cfg);
3009 tmp2 = mono_alloc_ireg (cfg);
3010 tmp3 = mono_alloc_ireg (cfg);
3011 tmp4 = mono_alloc_ireg (cfg);
3012 tmp5 = mono_alloc_ireg (cfg);
3014 /* tmp1 = 0 if the signs of the two inputs match, else 1 */
3015 INS (pos, OP_IXOR, tmp1, last_ins->sreg1, last_ins->sreg2);
3017 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
3018 INS (pos, OP_IXOR, tmp2, last_ins->dreg, last_ins->sreg2);
3019 INS (pos, OP_INOT, tmp3, tmp2, -1);
3021 /* OR(tmp1, tmp2) = 0 if both conditions are true */
3022 INS (pos, OP_IOR, tmp4, tmp3, tmp1);
3023 INS_IMM (pos, OP_SHR_IMM, tmp5, tmp4, 31);
3025 /* Now, if (tmp5 == 0) then overflow */
3026 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, tmp5, mips_zero);
3027 ins->dreg = -1;
3028 break;
3031 case OP_COND_EXC_NO:
3032 case OP_COND_EXC_INO:
3033 g_assert_not_reached ();
3034 break;
3036 case OP_COND_EXC_C:
3037 case OP_COND_EXC_IC:
3038 g_assert_not_reached ();
3039 break;
3041 case OP_COND_EXC_NC:
3042 case OP_COND_EXC_INC:
3043 g_assert_not_reached ();
3044 break;
3047 last_ins = ins;
3049 bb->last_ins = last_ins;
3050 bb->max_vreg = cfg->next_vreg;
3052 #if 1
3053 if (cfg->verbose_level > 2) {
3054 int idx = 0;
3056 g_print ("BASIC BLOCK %d (after lowering)\n", bb->block_num);
3057 MONO_BB_FOR_EACH_INS (bb, ins) {
3058 mono_print_ins_index (idx++, ins);
3062 #endif
3066 static guchar*
3067 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
3069 /* sreg is a float, dreg is an integer reg. mips_at is used as scratch */
3070 #if 1
3071 mips_truncwd (code, mips_ftemp, sreg);
3072 #else
3073 mips_cvtwd (code, mips_ftemp, sreg);
3074 #endif
3075 mips_mfc1 (code, dreg, mips_ftemp);
3076 if (!is_signed) {
3077 if (size == 1)
3078 mips_andi (code, dreg, dreg, 0xff);
3079 else if (size == 2) {
3080 mips_sll (code, dreg, dreg, 16);
3081 mips_srl (code, dreg, dreg, 16);
3083 } else {
3084 if (size == 1) {
3085 mips_sll (code, dreg, dreg, 24);
3086 mips_sra (code, dreg, dreg, 24);
3088 else if (size == 2) {
3089 mips_sll (code, dreg, dreg, 16);
3090 mips_sra (code, dreg, dreg, 16);
3093 return code;
3097 * emit_load_volatile_arguments:
3099 * Load volatile arguments from the stack to the original input registers.
3100 * Required before a tail call.
3102 static guint8 *
3103 emit_load_volatile_arguments(MonoCompile *cfg, guint8 *code)
3105 MonoMethod *method = cfg->method;
3106 MonoMethodSignature *sig;
3107 MonoInst *inst;
3108 CallInfo *cinfo;
3109 int i;
3111 sig = mono_method_signature (method);
3113 if (!cfg->arch.cinfo)
3114 cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
3115 cinfo = cfg->arch.cinfo;
3117 if (cinfo->struct_ret) {
3118 ArgInfo *ainfo = &cinfo->ret;
3119 inst = cfg->vret_addr;
3120 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3123 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3124 ArgInfo *ainfo = cinfo->args + i;
3125 inst = cfg->args [i];
3126 if (inst->opcode == OP_REGVAR) {
3127 if (ainfo->storage == ArgInIReg)
3128 MIPS_MOVE (code, ainfo->reg, inst->dreg);
3129 else if (ainfo->storage == ArgInFReg)
3130 g_assert_not_reached();
3131 else if (ainfo->storage == ArgOnStack) {
3132 /* do nothing */
3133 } else
3134 g_assert_not_reached ();
3135 } else {
3136 if (ainfo->storage == ArgInIReg) {
3137 g_assert (mips_is_imm16 (inst->inst_offset));
3138 switch (ainfo->size) {
3139 case 1:
3140 mips_lb (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3141 break;
3142 case 2:
3143 mips_lh (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3144 break;
3145 case 0: /* XXX */
3146 case 4:
3147 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3148 break;
3149 case 8:
3150 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
3151 mips_lw (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
3152 break;
3153 default:
3154 g_assert_not_reached ();
3155 break;
3157 } else if (ainfo->storage == ArgOnStack) {
3158 /* do nothing */
3159 } else if (ainfo->storage == ArgInFReg) {
3160 g_assert (mips_is_imm16 (inst->inst_offset));
3161 if (ainfo->size == 8) {
3162 #if _MIPS_SIM == _ABIO32
3163 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
3164 mips_lwc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
3165 #elif _MIPS_SIM == _ABIN32
3166 mips_ldc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3167 #endif
3169 else if (ainfo->size == 4)
3170 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3171 else
3172 g_assert_not_reached ();
3173 } else if (ainfo->storage == ArgStructByVal) {
3174 int i;
3175 int doffset = inst->inst_offset;
3177 g_assert (mips_is_imm16 (inst->inst_offset));
3178 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
3179 for (i = 0; i < ainfo->size; ++i) {
3180 mips_lw (code, ainfo->reg + i, inst->inst_basereg, doffset);
3181 doffset += SIZEOF_REGISTER;
3183 } else if (ainfo->storage == ArgStructByAddr) {
3184 g_assert (mips_is_imm16 (inst->inst_offset));
3185 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3186 } else
3187 g_assert_not_reached ();
3191 return code;
3194 static guint8*
3195 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
3197 int size = cfg->param_area;
3199 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3200 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3202 if (!size)
3203 return code;
3204 #if 0
3205 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3206 if (ppc_is_imm16 (-size)) {
3207 ppc_stwu (code, ppc_r0, -size, ppc_sp);
3208 } else {
3209 ppc_load (code, ppc_r12, -size);
3210 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r12);
3212 #endif
3213 return code;
3216 static guint8*
3217 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
3219 int size = cfg->param_area;
3221 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3222 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3224 if (!size)
3225 return code;
3226 #if 0
3227 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3228 if (ppc_is_imm16 (size)) {
3229 ppc_stwu (code, ppc_r0, size, ppc_sp);
3230 } else {
3231 ppc_load (code, ppc_r12, size);
3232 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r12);
3234 #endif
3235 return code;
3238 void
3239 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3241 MonoInst *ins;
3242 MonoCallInst *call;
3243 guint offset;
3244 guint8 *code = cfg->native_code + cfg->code_len;
3245 MonoInst *last_ins = NULL;
3246 guint last_offset = 0;
3247 int max_len, cpos;
3248 int ins_cnt = 0;
3250 /* we don't align basic blocks of loops on mips */
3252 if (cfg->verbose_level > 2)
3253 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3255 cpos = bb->max_offset;
3257 #if 0
3258 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
3259 MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
3260 g_assert (!mono_compile_aot);
3261 cpos += 20;
3262 if (bb->cil_code)
3263 cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
3264 /* this is not thread save, but good enough */
3265 /* fixme: howto handle overflows? */
3266 mips_load_const (code, mips_at, &cov->data [bb->dfn].count);
3267 mips_lw (code, mips_temp, mips_at, 0);
3268 mips_addiu (code, mips_temp, mips_temp, 1);
3269 mips_sw (code, mips_temp, mips_at, 0);
3271 #endif
3272 MONO_BB_FOR_EACH_INS (bb, ins) {
3273 offset = code - cfg->native_code;
3275 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3277 if (offset > (cfg->code_size - max_len - 16)) {
3278 cfg->code_size *= 2;
3279 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3280 code = cfg->native_code + offset;
3282 mono_debug_record_line_number (cfg, ins, offset);
3283 if (cfg->verbose_level > 2) {
3284 g_print (" @ 0x%x\t", offset);
3285 mono_print_ins_index (ins_cnt++, ins);
3287 /* Check for virtual regs that snuck by */
3288 g_assert ((ins->dreg >= -1) && (ins->dreg < 32));
3290 switch (ins->opcode) {
3291 case OP_RELAXED_NOP:
3292 case OP_NOP:
3293 case OP_DUMMY_USE:
3294 case OP_DUMMY_STORE:
3295 case OP_NOT_REACHED:
3296 case OP_NOT_NULL:
3297 break;
3298 case OP_IL_SEQ_POINT:
3299 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3300 break;
3301 case OP_SEQ_POINT: {
3302 if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
3303 guint32 addr = (guint32)ss_trigger_page;
3305 mips_load_const (code, mips_t9, addr);
3306 mips_lw (code, mips_t9, mips_t9, 0);
3309 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3312 * A placeholder for a possible breakpoint inserted by
3313 * mono_arch_set_breakpoint ().
3315 /* mips_load_const () + mips_lw */
3316 mips_nop (code);
3317 mips_nop (code);
3318 mips_nop (code);
3319 break;
3321 case OP_TLS_GET:
3322 g_assert_not_reached();
3323 #if 0
3324 emit_tls_access (code, ins->dreg, ins->inst_offset);
3325 #endif
3326 break;
3327 case OP_BIGMUL:
3328 mips_mult (code, ins->sreg1, ins->sreg2);
3329 mips_mflo (code, ins->dreg);
3330 mips_mfhi (code, ins->dreg+1);
3331 break;
3332 case OP_BIGMUL_UN:
3333 mips_multu (code, ins->sreg1, ins->sreg2);
3334 mips_mflo (code, ins->dreg);
3335 mips_mfhi (code, ins->dreg+1);
3336 break;
3337 case OP_MEMORY_BARRIER:
3338 mips_sync (code, 0);
3339 break;
3340 case OP_STOREI1_MEMBASE_IMM:
3341 mips_load_const (code, mips_temp, ins->inst_imm);
3342 if (mips_is_imm16 (ins->inst_offset)) {
3343 mips_sb (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3344 } else {
3345 mips_load_const (code, mips_at, ins->inst_offset);
3346 mips_sb (code, mips_temp, mips_at, ins->inst_destbasereg);
3348 break;
3349 case OP_STOREI2_MEMBASE_IMM:
3350 mips_load_const (code, mips_temp, ins->inst_imm);
3351 if (mips_is_imm16 (ins->inst_offset)) {
3352 mips_sh (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3353 } else {
3354 mips_load_const (code, mips_at, ins->inst_offset);
3355 mips_sh (code, mips_temp, mips_at, ins->inst_destbasereg);
3357 break;
3358 case OP_STOREI8_MEMBASE_IMM:
3359 mips_load_const (code, mips_temp, ins->inst_imm);
3360 if (mips_is_imm16 (ins->inst_offset)) {
3361 mips_sd (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3362 } else {
3363 mips_load_const (code, mips_at, ins->inst_offset);
3364 mips_sd (code, mips_temp, mips_at, ins->inst_destbasereg);
3366 break;
3367 case OP_STORE_MEMBASE_IMM:
3368 case OP_STOREI4_MEMBASE_IMM:
3369 mips_load_const (code, mips_temp, ins->inst_imm);
3370 if (mips_is_imm16 (ins->inst_offset)) {
3371 mips_sw (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3372 } else {
3373 mips_load_const (code, mips_at, ins->inst_offset);
3374 mips_sw (code, mips_temp, mips_at, ins->inst_destbasereg);
3376 break;
3377 case OP_STOREI1_MEMBASE_REG:
3378 if (mips_is_imm16 (ins->inst_offset)) {
3379 mips_sb (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3380 } else {
3381 mips_load_const (code, mips_at, ins->inst_offset);
3382 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3383 mips_sb (code, ins->sreg1, mips_at, 0);
3385 break;
3386 case OP_STOREI2_MEMBASE_REG:
3387 if (mips_is_imm16 (ins->inst_offset)) {
3388 mips_sh (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3389 } else {
3390 mips_load_const (code, mips_at, ins->inst_offset);
3391 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3392 mips_sh (code, ins->sreg1, mips_at, 0);
3394 break;
3395 case OP_STORE_MEMBASE_REG:
3396 case OP_STOREI4_MEMBASE_REG:
3397 if (mips_is_imm16 (ins->inst_offset)) {
3398 mips_sw (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3399 } else {
3400 mips_load_const (code, mips_at, ins->inst_offset);
3401 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3402 mips_sw (code, ins->sreg1, mips_at, 0);
3404 break;
3405 case OP_STOREI8_MEMBASE_REG:
3406 if (mips_is_imm16 (ins->inst_offset)) {
3407 mips_sd (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3408 } else {
3409 mips_load_const (code, mips_at, ins->inst_offset);
3410 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3411 mips_sd (code, ins->sreg1, mips_at, 0);
3413 break;
3414 case OP_LOADU4_MEM:
3415 g_assert_not_reached ();
3416 //x86_mov_reg_imm (code, ins->dreg, ins->inst_p0);
3417 //x86_mov_reg_membase (code, ins->dreg, ins->dreg, 0, 4);
3418 break;
3419 case OP_LOADI8_MEMBASE:
3420 if (mips_is_imm16 (ins->inst_offset)) {
3421 mips_ld (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3422 } else {
3423 mips_load_const (code, mips_at, ins->inst_offset);
3424 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3425 mips_ld (code, ins->dreg, mips_at, 0);
3427 break;
3428 case OP_LOAD_MEMBASE:
3429 case OP_LOADI4_MEMBASE:
3430 case OP_LOADU4_MEMBASE:
3431 g_assert (ins->dreg != -1);
3432 if (mips_is_imm16 (ins->inst_offset)) {
3433 mips_lw (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3434 } else {
3435 mips_load_const (code, mips_at, ins->inst_offset);
3436 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3437 mips_lw (code, ins->dreg, mips_at, 0);
3439 break;
3440 case OP_LOADI1_MEMBASE:
3441 if (mips_is_imm16 (ins->inst_offset)) {
3442 mips_lb (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3443 } else {
3444 mips_load_const (code, mips_at, ins->inst_offset);
3445 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3446 mips_lb (code, ins->dreg, mips_at, 0);
3448 break;
3449 case OP_LOADU1_MEMBASE:
3450 if (mips_is_imm16 (ins->inst_offset)) {
3451 mips_lbu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3452 } else {
3453 mips_load_const (code, mips_at, ins->inst_offset);
3454 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3455 mips_lbu (code, ins->dreg, mips_at, 0);
3457 break;
3458 case OP_LOADI2_MEMBASE:
3459 if (mips_is_imm16 (ins->inst_offset)) {
3460 mips_lh (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3461 } else {
3462 mips_load_const (code, mips_at, ins->inst_offset);
3463 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3464 mips_lh (code, ins->dreg, mips_at, 0);
3466 break;
3467 case OP_LOADU2_MEMBASE:
3468 if (mips_is_imm16 (ins->inst_offset)) {
3469 mips_lhu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3470 } else {
3471 mips_load_const (code, mips_at, ins->inst_offset);
3472 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3473 mips_lhu (code, ins->dreg, mips_at, 0);
3475 break;
3476 case OP_ICONV_TO_I1:
3477 mips_sll (code, mips_at, ins->sreg1, 24);
3478 mips_sra (code, ins->dreg, mips_at, 24);
3479 break;
3480 case OP_ICONV_TO_I2:
3481 mips_sll (code, mips_at, ins->sreg1, 16);
3482 mips_sra (code, ins->dreg, mips_at, 16);
3483 break;
3484 case OP_ICONV_TO_U1:
3485 mips_andi (code, ins->dreg, ins->sreg1, 0xff);
3486 break;
3487 case OP_ICONV_TO_U2:
3488 mips_sll (code, mips_at, ins->sreg1, 16);
3489 mips_srl (code, ins->dreg, mips_at, 16);
3490 break;
3491 case OP_MIPS_SLT:
3492 mips_slt (code, ins->dreg, ins->sreg1, ins->sreg2);
3493 break;
3494 case OP_MIPS_SLTI:
3495 g_assert (mips_is_imm16 (ins->inst_imm));
3496 mips_slti (code, ins->dreg, ins->sreg1, ins->inst_imm);
3497 break;
3498 case OP_MIPS_SLTU:
3499 mips_sltu (code, ins->dreg, ins->sreg1, ins->sreg2);
3500 break;
3501 case OP_MIPS_SLTIU:
3502 g_assert (mips_is_imm16 (ins->inst_imm));
3503 mips_sltiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3504 break;
3505 case OP_BREAK:
3507 * gdb does not like encountering the hw breakpoint ins in the debugged code.
3508 * So instead of emitting a trap, we emit a call a C function and place a
3509 * breakpoint there.
3511 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3512 (gpointer)"mono_break");
3513 mips_load (code, mips_t9, 0x1f1f1f1f);
3514 mips_jalr (code, mips_t9, mips_ra);
3515 mips_nop (code);
3516 break;
3517 case OP_IADD:
3518 mips_addu (code, ins->dreg, ins->sreg1, ins->sreg2);
3519 break;
3520 case OP_LADD:
3521 mips_daddu (code, ins->dreg, ins->sreg1, ins->sreg2);
3522 break;
3524 case OP_ADD_IMM:
3525 case OP_IADD_IMM:
3526 g_assert (mips_is_imm16 (ins->inst_imm));
3527 mips_addiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3528 break;
3529 case OP_LADD_IMM:
3530 g_assert (mips_is_imm16 (ins->inst_imm));
3531 mips_daddiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3532 break;
3534 case OP_ISUB:
3535 mips_subu (code, ins->dreg, ins->sreg1, ins->sreg2);
3536 break;
3537 case OP_LSUB:
3538 mips_dsubu (code, ins->dreg, ins->sreg1, ins->sreg2);
3539 break;
3541 case OP_ISUB_IMM:
3542 case OP_SUB_IMM:
3543 // we add the negated value
3544 g_assert (mips_is_imm16 (-ins->inst_imm));
3545 mips_addiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3546 break;
3548 case OP_LSUB_IMM:
3549 // we add the negated value
3550 g_assert (mips_is_imm16 (-ins->inst_imm));
3551 mips_daddiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3552 break;
3554 case OP_IAND:
3555 case OP_LAND:
3556 mips_and (code, ins->dreg, ins->sreg1, ins->sreg2);
3557 break;
3559 case OP_AND_IMM:
3560 case OP_IAND_IMM:
3561 case OP_LAND_IMM:
3562 g_assert (!(ins->inst_imm & 0xffff0000));
3563 mips_andi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3564 break;
3566 case OP_IDIV:
3567 case OP_IREM: {
3568 guint32 *divisor_is_m1;
3569 guint32 *dividend_is_minvalue;
3570 guint32 *divisor_is_zero;
3572 mips_load_const (code, mips_at, -1);
3573 divisor_is_m1 = (guint32 *)(void *)code;
3574 mips_bne (code, ins->sreg2, mips_at, 0);
3575 mips_lui (code, mips_at, mips_zero, 0x8000);
3576 dividend_is_minvalue = (guint32 *)(void *)code;
3577 mips_bne (code, ins->sreg1, mips_at, 0);
3578 mips_nop (code);
3580 /* Divide Int32.MinValue by -1 -- throw exception */
3581 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3583 mips_patch (divisor_is_m1, (guint32)code);
3584 mips_patch (dividend_is_minvalue, (guint32)code);
3586 /* Put divide in branch delay slot (NOT YET) */
3587 divisor_is_zero = (guint32 *)(void *)code;
3588 mips_bne (code, ins->sreg2, mips_zero, 0);
3589 mips_nop (code);
3591 /* Divide by zero -- throw exception */
3592 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3594 mips_patch (divisor_is_zero, (guint32)code);
3595 mips_div (code, ins->sreg1, ins->sreg2);
3596 if (ins->opcode == OP_IDIV)
3597 mips_mflo (code, ins->dreg);
3598 else
3599 mips_mfhi (code, ins->dreg);
3600 break;
3602 case OP_IDIV_UN:
3603 case OP_IREM_UN: {
3604 guint32 *divisor_is_zero = (guint32 *)(void *)code;
3606 /* Put divide in branch delay slot (NOT YET) */
3607 mips_bne (code, ins->sreg2, mips_zero, 0);
3608 mips_nop (code);
3610 /* Divide by zero -- throw exception */
3611 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3613 mips_patch (divisor_is_zero, (guint32)code);
3614 mips_divu (code, ins->sreg1, ins->sreg2);
3615 if (ins->opcode == OP_IDIV_UN)
3616 mips_mflo (code, ins->dreg);
3617 else
3618 mips_mfhi (code, ins->dreg);
3619 break;
3621 case OP_DIV_IMM:
3622 g_assert_not_reached ();
3623 #if 0
3624 ppc_load (code, ppc_r12, ins->inst_imm);
3625 ppc_divwod (code, ins->dreg, ins->sreg1, ppc_r12);
3626 ppc_mfspr (code, ppc_r0, ppc_xer);
3627 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3628 /* FIXME: use OverflowException for 0x80000000/-1 */
3629 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3630 #endif
3631 g_assert_not_reached();
3632 break;
3633 case OP_REM_IMM:
3634 g_assert_not_reached ();
3635 case OP_IOR:
3636 mips_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3637 break;
3638 case OP_OR_IMM:
3639 case OP_IOR_IMM:
3640 g_assert (!(ins->inst_imm & 0xffff0000));
3641 mips_ori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3642 break;
3643 case OP_IXOR:
3644 mips_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3645 break;
3646 case OP_XOR_IMM:
3647 case OP_IXOR_IMM:
3648 /* unsigned 16-bit immediate */
3649 g_assert (!(ins->inst_imm & 0xffff0000));
3650 mips_xori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3651 break;
3652 case OP_ISHL:
3653 mips_sllv (code, ins->dreg, ins->sreg1, ins->sreg2);
3654 break;
3655 case OP_SHL_IMM:
3656 case OP_ISHL_IMM:
3657 mips_sll (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3658 break;
3659 case OP_ISHR:
3660 mips_srav (code, ins->dreg, ins->sreg1, ins->sreg2);
3661 break;
3662 case OP_LSHR:
3663 mips_dsrav (code, ins->dreg, ins->sreg1, ins->sreg2);
3664 break;
3665 case OP_SHR_IMM:
3666 case OP_ISHR_IMM:
3667 mips_sra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3668 break;
3669 case OP_LSHR_IMM:
3670 mips_dsra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3671 break;
3672 case OP_SHR_UN_IMM:
3673 case OP_ISHR_UN_IMM:
3674 mips_srl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3675 break;
3676 case OP_LSHR_UN_IMM:
3677 mips_dsrl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3678 break;
3679 case OP_ISHR_UN:
3680 mips_srlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3681 break;
3682 case OP_LSHR_UN:
3683 mips_dsrlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3684 break;
3685 case OP_INOT:
3686 case OP_LNOT:
3687 mips_nor (code, ins->dreg, mips_zero, ins->sreg1);
3688 break;
3689 case OP_INEG:
3690 mips_subu (code, ins->dreg, mips_zero, ins->sreg1);
3691 break;
3692 case OP_LNEG:
3693 mips_dsubu (code, ins->dreg, mips_zero, ins->sreg1);
3694 break;
3695 case OP_IMUL:
3696 #if USE_MUL
3697 mips_mul (code, ins->dreg, ins->sreg1, ins->sreg2);
3698 #else
3699 mips_mult (code, ins->sreg1, ins->sreg2);
3700 mips_mflo (code, ins->dreg);
3701 mips_nop (code);
3702 mips_nop (code);
3703 #endif
3704 break;
3705 #if SIZEOF_REGISTER == 8
3706 case OP_LMUL:
3707 mips_dmult (code, ins->sreg1, ins->sreg2);
3708 mips_mflo (code, ins->dreg);
3709 break;
3710 #endif
3711 case OP_IMUL_OVF: {
3712 guint32 *patch;
3713 mips_mult (code, ins->sreg1, ins->sreg2);
3714 mips_mflo (code, ins->dreg);
3715 mips_mfhi (code, mips_at);
3716 mips_nop (code);
3717 mips_nop (code);
3718 mips_sra (code, mips_temp, ins->dreg, 31);
3719 patch = (guint32 *)(void *)code;
3720 mips_beq (code, mips_temp, mips_at, 0);
3721 mips_nop (code);
3722 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3723 mips_patch (patch, (guint32)code);
3724 break;
3726 case OP_IMUL_OVF_UN: {
3727 guint32 *patch;
3728 mips_mult (code, ins->sreg1, ins->sreg2);
3729 mips_mflo (code, ins->dreg);
3730 mips_mfhi (code, mips_at);
3731 mips_nop (code);
3732 mips_nop (code);
3733 patch = (guint32 *)(void *)code;
3734 mips_beq (code, mips_at, mips_zero, 0);
3735 mips_nop (code);
3736 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3737 mips_patch (patch, (guint32)code);
3738 break;
3740 case OP_ICONST:
3741 mips_load_const (code, ins->dreg, ins->inst_c0);
3742 break;
3743 #if SIZEOF_REGISTER == 8
3744 case OP_I8CONST:
3745 mips_load_const (code, ins->dreg, ins->inst_c0);
3746 break;
3747 #endif
3748 case OP_AOTCONST:
3749 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3750 mips_load (code, ins->dreg, 0);
3751 break;
3753 case OP_MIPS_MTC1S:
3754 mips_mtc1 (code, ins->dreg, ins->sreg1);
3755 break;
3756 case OP_MIPS_MTC1S_2:
3757 mips_mtc1 (code, ins->dreg, ins->sreg1);
3758 mips_mtc1 (code, ins->dreg+1, ins->sreg2);
3759 break;
3760 case OP_MIPS_MFC1S:
3761 mips_mfc1 (code, ins->dreg, ins->sreg1);
3762 break;
3763 case OP_MIPS_MTC1D:
3764 mips_dmtc1 (code, ins->dreg, ins->sreg1);
3765 break;
3766 case OP_MIPS_MFC1D:
3767 #if 0
3768 mips_dmfc1 (code, ins->dreg, ins->sreg1);
3769 #else
3770 mips_mfc1 (code, ins->dreg, ins->sreg1 + ls_word_idx);
3771 mips_mfc1 (code, ins->dreg+1, ins->sreg1 + ms_word_idx);
3772 #endif
3773 break;
3775 case OP_ICONV_TO_I4:
3776 case OP_ICONV_TO_U4:
3777 case OP_MOVE:
3778 if (ins->dreg != ins->sreg1)
3779 MIPS_MOVE (code, ins->dreg, ins->sreg1);
3780 break;
3781 #if SIZEOF_REGISTER == 8
3782 case OP_ZEXT_I4:
3783 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3784 mips_dsrl (code, ins->dreg, ins->dreg, 32);
3785 break;
3786 case OP_SEXT_I4:
3787 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3788 mips_dsra (code, ins->dreg, ins->dreg, 32);
3789 break;
3790 #endif
3791 case OP_SETLRET: {
3792 int lsreg = mips_v0 + ls_word_idx;
3793 int msreg = mips_v0 + ms_word_idx;
3795 /* Get sreg1 into lsreg, sreg2 into msreg */
3797 if (ins->sreg1 == msreg) {
3798 if (ins->sreg1 != mips_at)
3799 MIPS_MOVE (code, mips_at, ins->sreg1);
3800 if (ins->sreg2 != msreg)
3801 MIPS_MOVE (code, msreg, ins->sreg2);
3802 MIPS_MOVE (code, lsreg, mips_at);
3804 else {
3805 if (ins->sreg2 != msreg)
3806 MIPS_MOVE (code, msreg, ins->sreg2);
3807 if (ins->sreg1 != lsreg)
3808 MIPS_MOVE (code, lsreg, ins->sreg1);
3810 break;
3812 case OP_FMOVE:
3813 if (ins->dreg != ins->sreg1) {
3814 mips_fmovd (code, ins->dreg, ins->sreg1);
3816 break;
3817 case OP_MOVE_F_TO_I4:
3818 mips_cvtsd (code, mips_ftemp, ins->sreg1);
3819 mips_mfc1 (code, ins->dreg, mips_ftemp);
3820 break;
3821 case OP_MOVE_I4_TO_F:
3822 mips_mtc1 (code, ins->dreg, ins->sreg1);
3823 mips_cvtds (code, ins->dreg, ins->dreg);
3824 break;
3825 case OP_MIPS_CVTSD:
3826 /* Convert from double to float and leave it there */
3827 mips_cvtsd (code, ins->dreg, ins->sreg1);
3828 break;
3829 case OP_FCONV_TO_R4:
3830 #if 0
3831 mips_cvtsd (code, ins->dreg, ins->sreg1);
3832 #else
3833 /* Just a move, no precision change */
3834 if (ins->dreg != ins->sreg1) {
3835 mips_fmovd (code, ins->dreg, ins->sreg1);
3837 #endif
3838 break;
3839 case OP_JMP:
3840 code = emit_load_volatile_arguments(cfg, code);
3843 * Pop our stack, then jump to specified method (tail-call)
3844 * Keep in sync with mono_arch_emit_epilog
3846 code = mono_arch_emit_epilog_sub (cfg, code);
3848 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code,
3849 MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3850 mips_load (code, mips_t9, 0);
3851 mips_jr (code, mips_t9);
3852 mips_nop (code);
3853 break;
3854 case OP_CHECK_THIS:
3855 /* ensure ins->sreg1 is not NULL */
3856 mips_lw (code, mips_zero, ins->sreg1, 0);
3857 break;
3858 case OP_ARGLIST: {
3859 g_assert (mips_is_imm16 (cfg->sig_cookie));
3860 mips_lw (code, mips_at, cfg->frame_reg, cfg->sig_cookie);
3861 mips_sw (code, mips_at, ins->sreg1, 0);
3862 break;
3864 case OP_FCALL:
3865 case OP_LCALL:
3866 case OP_VCALL:
3867 case OP_VCALL2:
3868 case OP_VOIDCALL:
3869 case OP_CALL:
3870 case OP_FCALL_REG:
3871 case OP_LCALL_REG:
3872 case OP_VCALL_REG:
3873 case OP_VCALL2_REG:
3874 case OP_VOIDCALL_REG:
3875 case OP_CALL_REG:
3876 case OP_FCALL_MEMBASE:
3877 case OP_LCALL_MEMBASE:
3878 case OP_VCALL_MEMBASE:
3879 case OP_VCALL2_MEMBASE:
3880 case OP_VOIDCALL_MEMBASE:
3881 case OP_CALL_MEMBASE:
3882 call = (MonoCallInst*)ins;
3883 switch (ins->opcode) {
3884 case OP_FCALL:
3885 case OP_LCALL:
3886 case OP_VCALL:
3887 case OP_VCALL2:
3888 case OP_VOIDCALL:
3889 case OP_CALL:
3890 if (ins->flags & MONO_INST_HAS_METHOD) {
3891 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3892 mips_load (code, mips_t9, call->method);
3894 else {
3895 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3896 mips_load (code, mips_t9, call->fptr);
3898 mips_jalr (code, mips_t9, mips_ra);
3899 mips_nop (code);
3900 break;
3901 case OP_FCALL_REG:
3902 case OP_LCALL_REG:
3903 case OP_VCALL_REG:
3904 case OP_VCALL2_REG:
3905 case OP_VOIDCALL_REG:
3906 case OP_CALL_REG:
3907 MIPS_MOVE (code, mips_t9, ins->sreg1);
3908 mips_jalr (code, mips_t9, mips_ra);
3909 mips_nop (code);
3910 break;
3911 case OP_FCALL_MEMBASE:
3912 case OP_LCALL_MEMBASE:
3913 case OP_VCALL_MEMBASE:
3914 case OP_VCALL2_MEMBASE:
3915 case OP_VOIDCALL_MEMBASE:
3916 case OP_CALL_MEMBASE:
3917 mips_lw (code, mips_t9, ins->sreg1, ins->inst_offset);
3918 mips_jalr (code, mips_t9, mips_ra);
3919 mips_nop (code);
3920 break;
3922 #if PROMOTE_R4_TO_R8
3923 /* returned an FP R4 (single), promote to R8 (double) in place */
3924 switch (ins->opcode) {
3925 case OP_FCALL:
3926 case OP_FCALL_REG:
3927 case OP_FCALL_MEMBASE:
3928 if (call->signature->ret->type == MONO_TYPE_R4)
3929 mips_cvtds (code, mips_f0, mips_f0);
3930 break;
3931 default:
3932 break;
3934 #endif
3935 break;
3936 case OP_LOCALLOC: {
3937 int area_offset = cfg->param_area;
3939 /* Round up ins->sreg1, mips_at ends up holding size */
3940 mips_addiu (code, mips_at, ins->sreg1, 31);
3941 mips_addiu (code, mips_temp, mips_zero, ~31);
3942 mips_and (code, mips_at, mips_at, mips_temp);
3944 mips_subu (code, mips_sp, mips_sp, mips_at);
3945 g_assert (mips_is_imm16 (area_offset));
3946 mips_addiu (code, ins->dreg, mips_sp, area_offset);
3948 if (ins->flags & MONO_INST_INIT) {
3949 guint32 *buf;
3951 buf = (guint32*)(void*)code;
3952 mips_beq (code, mips_at, mips_zero, 0);
3953 mips_nop (code);
3955 mips_move (code, mips_temp, ins->dreg);
3956 mips_sb (code, mips_zero, mips_temp, 0);
3957 mips_addiu (code, mips_at, mips_at, -1);
3958 mips_bne (code, mips_at, mips_zero, -3);
3959 mips_addiu (code, mips_temp, mips_temp, 1);
3961 mips_patch (buf, (guint32)code);
3963 break;
3965 case OP_THROW: {
3966 gpointer addr = mono_arch_get_throw_exception(NULL, FALSE);
3967 mips_move (code, mips_a0, ins->sreg1);
3968 mips_call (code, mips_t9, addr);
3969 mips_break (code, 0xfc);
3970 break;
3972 case OP_RETHROW: {
3973 gpointer addr = mono_arch_get_rethrow_exception(NULL, FALSE);
3974 mips_move (code, mips_a0, ins->sreg1);
3975 mips_call (code, mips_t9, addr);
3976 mips_break (code, 0xfb);
3977 break;
3979 case OP_START_HANDLER: {
3981 * The START_HANDLER instruction marks the beginning of
3982 * a handler block. It is called using a call
3983 * instruction, so mips_ra contains the return address.
3984 * Since the handler executes in the same stack frame
3985 * as the method itself, we can't use save/restore to
3986 * save the return address. Instead, we save it into
3987 * a dedicated variable.
3989 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3990 g_assert (spvar->inst_basereg != mips_sp);
3991 code = emit_reserve_param_area (cfg, code);
3993 if (mips_is_imm16 (spvar->inst_offset)) {
3994 mips_sw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
3995 } else {
3996 mips_load_const (code, mips_at, spvar->inst_offset);
3997 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
3998 mips_sw (code, mips_ra, mips_at, 0);
4000 break;
4002 case OP_ENDFILTER: {
4003 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4004 g_assert (spvar->inst_basereg != mips_sp);
4005 code = emit_unreserve_param_area (cfg, code);
4007 if (ins->sreg1 != mips_v0)
4008 MIPS_MOVE (code, mips_v0, ins->sreg1);
4009 if (mips_is_imm16 (spvar->inst_offset)) {
4010 mips_lw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
4011 } else {
4012 mips_load_const (code, mips_at, spvar->inst_offset);
4013 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
4014 mips_lw (code, mips_ra, mips_at, 0);
4016 mips_jr (code, mips_ra);
4017 mips_nop (code);
4018 break;
4020 case OP_ENDFINALLY: {
4021 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4022 g_assert (spvar->inst_basereg != mips_sp);
4023 code = emit_unreserve_param_area (cfg, code);
4024 mips_lw (code, mips_t9, spvar->inst_basereg, spvar->inst_offset);
4025 mips_jalr (code, mips_t9, mips_ra);
4026 mips_nop (code);
4027 break;
4029 case OP_CALL_HANDLER:
4030 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4031 mips_lui (code, mips_t9, mips_zero, 0);
4032 mips_addiu (code, mips_t9, mips_t9, 0);
4033 mips_jalr (code, mips_t9, mips_ra);
4034 mips_nop (code);
4035 /*FIXME should it be before the NOP or not? Does MIPS has a delay slot like sparc?*/
4036 mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
4037 break;
4038 case OP_LABEL:
4039 ins->inst_c0 = code - cfg->native_code;
4040 break;
4041 case OP_BR:
4042 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4043 if (cfg->arch.long_branch) {
4044 mips_lui (code, mips_at, mips_zero, 0);
4045 mips_addiu (code, mips_at, mips_at, 0);
4046 mips_jr (code, mips_at);
4047 mips_nop (code);
4049 else {
4050 mips_beq (code, mips_zero, mips_zero, 0);
4051 mips_nop (code);
4053 break;
4054 case OP_BR_REG:
4055 mips_jr (code, ins->sreg1);
4056 mips_nop (code);
4057 break;
4058 case OP_SWITCH: {
4059 int i;
4061 max_len += 4 * GPOINTER_TO_INT (ins->klass);
4062 if (offset > (cfg->code_size - max_len - 16)) {
4063 cfg->code_size += max_len;
4064 cfg->code_size *= 2;
4065 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4066 code = cfg->native_code + offset;
4068 g_assert (ins->sreg1 != -1);
4069 mips_sll (code, mips_at, ins->sreg1, 2);
4070 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS))
4071 MIPS_MOVE (code, mips_t8, mips_ra);
4072 mips_bgezal (code, mips_zero, 1); /* bal */
4073 mips_nop (code);
4074 mips_addu (code, mips_t9, mips_ra, mips_at);
4075 /* Table is 16 or 20 bytes from target of bal above */
4076 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS)) {
4077 MIPS_MOVE (code, mips_ra, mips_t8);
4078 mips_lw (code, mips_t9, mips_t9, 20);
4080 else
4081 mips_lw (code, mips_t9, mips_t9, 16);
4082 mips_jalr (code, mips_t9, mips_t8);
4083 mips_nop (code);
4084 for (i = 0; i < GPOINTER_TO_INT (ins->klass); ++i)
4085 mips_emit32 (code, 0xfefefefe);
4086 break;
4088 case OP_CEQ:
4089 case OP_ICEQ:
4090 mips_addiu (code, ins->dreg, mips_zero, 1);
4091 mips_beq (code, mips_at, mips_zero, 2);
4092 mips_nop (code);
4093 MIPS_MOVE (code, ins->dreg, mips_zero);
4094 break;
4095 case OP_CLT:
4096 case OP_CLT_UN:
4097 case OP_ICLT:
4098 case OP_ICLT_UN:
4099 mips_addiu (code, ins->dreg, mips_zero, 1);
4100 mips_bltz (code, mips_at, 2);
4101 mips_nop (code);
4102 MIPS_MOVE (code, ins->dreg, mips_zero);
4103 break;
4104 case OP_CGT:
4105 case OP_CGT_UN:
4106 case OP_ICGT:
4107 case OP_ICGT_UN:
4108 mips_addiu (code, ins->dreg, mips_zero, 1);
4109 mips_bgtz (code, mips_at, 2);
4110 mips_nop (code);
4111 MIPS_MOVE (code, ins->dreg, mips_zero);
4112 break;
4114 case OP_MIPS_COND_EXC_EQ:
4115 case OP_MIPS_COND_EXC_GE:
4116 case OP_MIPS_COND_EXC_GT:
4117 case OP_MIPS_COND_EXC_LE:
4118 case OP_MIPS_COND_EXC_LT:
4119 case OP_MIPS_COND_EXC_NE_UN:
4120 case OP_MIPS_COND_EXC_GE_UN:
4121 case OP_MIPS_COND_EXC_GT_UN:
4122 case OP_MIPS_COND_EXC_LE_UN:
4123 case OP_MIPS_COND_EXC_LT_UN:
4125 case OP_MIPS_COND_EXC_OV:
4126 case OP_MIPS_COND_EXC_NO:
4127 case OP_MIPS_COND_EXC_C:
4128 case OP_MIPS_COND_EXC_NC:
4130 case OP_MIPS_COND_EXC_IEQ:
4131 case OP_MIPS_COND_EXC_IGE:
4132 case OP_MIPS_COND_EXC_IGT:
4133 case OP_MIPS_COND_EXC_ILE:
4134 case OP_MIPS_COND_EXC_ILT:
4135 case OP_MIPS_COND_EXC_INE_UN:
4136 case OP_MIPS_COND_EXC_IGE_UN:
4137 case OP_MIPS_COND_EXC_IGT_UN:
4138 case OP_MIPS_COND_EXC_ILE_UN:
4139 case OP_MIPS_COND_EXC_ILT_UN:
4141 case OP_MIPS_COND_EXC_IOV:
4142 case OP_MIPS_COND_EXC_INO:
4143 case OP_MIPS_COND_EXC_IC:
4144 case OP_MIPS_COND_EXC_INC: {
4145 guint32 *skip;
4146 guint32 *throw;
4148 /* If the condition is true, raise the exception */
4150 /* need to reverse test to skip around exception raising */
4152 /* For the moment, branch around a branch to avoid reversing
4153 the tests. */
4155 /* Remember, an unpatched branch to 0 branches to the delay slot */
4156 switch (ins->opcode) {
4157 case OP_MIPS_COND_EXC_EQ:
4158 throw = (guint32 *)(void *)code;
4159 mips_beq (code, ins->sreg1, ins->sreg2, 0);
4160 mips_nop (code);
4161 break;
4163 case OP_MIPS_COND_EXC_NE_UN:
4164 throw = (guint32 *)(void *)code;
4165 mips_bne (code, ins->sreg1, ins->sreg2, 0);
4166 mips_nop (code);
4167 break;
4169 case OP_MIPS_COND_EXC_LE_UN:
4170 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
4171 throw = (guint32 *)(void *)code;
4172 mips_beq (code, mips_at, mips_zero, 0);
4173 mips_nop (code);
4174 break;
4176 case OP_MIPS_COND_EXC_GT:
4177 mips_slt (code, mips_at, ins->sreg2, ins->sreg1);
4178 throw = (guint32 *)(void *)code;
4179 mips_bne (code, mips_at, mips_zero, 0);
4180 mips_nop (code);
4181 break;
4183 case OP_MIPS_COND_EXC_GT_UN:
4184 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
4185 throw = (guint32 *)(void *)code;
4186 mips_bne (code, mips_at, mips_zero, 0);
4187 mips_nop (code);
4188 break;
4190 case OP_MIPS_COND_EXC_LT:
4191 mips_slt (code, mips_at, ins->sreg1, ins->sreg2);
4192 throw = (guint32 *)(void *)code;
4193 mips_bne (code, mips_at, mips_zero, 0);
4194 mips_nop (code);
4195 break;
4197 case OP_MIPS_COND_EXC_LT_UN:
4198 mips_sltu (code, mips_at, ins->sreg1, ins->sreg2);
4199 throw = (guint32 *)(void *)code;
4200 mips_bne (code, mips_at, mips_zero, 0);
4201 mips_nop (code);
4202 break;
4204 default:
4205 /* Not yet implemented */
4206 g_warning ("NYI conditional exception %s\n", mono_inst_name (ins->opcode));
4207 g_assert_not_reached ();
4209 skip = (guint32 *)(void *)code;
4210 mips_beq (code, mips_zero, mips_zero, 0);
4211 mips_nop (code);
4212 mips_patch (throw, (guint32)code);
4213 code = mips_emit_exc_by_name (code, ins->inst_p1);
4214 mips_patch (skip, (guint32)code);
4215 cfg->bb_exit->max_offset += 24;
4216 break;
4218 case OP_MIPS_BEQ:
4219 case OP_MIPS_BNE:
4220 case OP_MIPS_BGEZ:
4221 case OP_MIPS_BGTZ:
4222 case OP_MIPS_BLEZ:
4223 case OP_MIPS_BLTZ:
4224 code = mips_emit_cond_branch (cfg, code, ins->opcode, ins);
4225 break;
4227 /* floating point opcodes */
4228 case OP_R8CONST:
4229 #if 0
4230 if (((guint32)ins->inst_p0) & (1 << 15))
4231 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4232 else
4233 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4234 mips_ldc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4235 #else
4236 mips_load_const (code, mips_at, ins->inst_p0);
4237 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4238 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4239 #endif
4240 break;
4241 case OP_R4CONST:
4242 if (((guint32)ins->inst_p0) & (1 << 15))
4243 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4244 else
4245 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4246 mips_lwc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4247 #if PROMOTE_R4_TO_R8
4248 mips_cvtds (code, ins->dreg, ins->dreg);
4249 #endif
4250 break;
4251 case OP_STORER8_MEMBASE_REG:
4252 if (mips_is_imm16 (ins->inst_offset)) {
4253 #if _MIPS_SIM == _ABIO32
4254 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset + ls_word_offset);
4255 mips_swc1 (code, ins->sreg1+1, ins->inst_destbasereg, ins->inst_offset + ms_word_offset);
4256 #elif _MIPS_SIM == _ABIN32
4257 mips_sdc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4258 #endif
4259 } else {
4260 mips_load_const (code, mips_at, ins->inst_offset);
4261 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
4262 mips_swc1 (code, ins->sreg1, mips_at, ls_word_offset);
4263 mips_swc1 (code, ins->sreg1+1, mips_at, ms_word_offset);
4265 break;
4266 case OP_LOADR8_MEMBASE:
4267 if (mips_is_imm16 (ins->inst_offset)) {
4268 #if _MIPS_SIM == _ABIO32
4269 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset + ls_word_offset);
4270 mips_lwc1 (code, ins->dreg+1, ins->inst_basereg, ins->inst_offset + ms_word_offset);
4271 #elif _MIPS_SIM == _ABIN32
4272 mips_ldc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4273 #endif
4274 } else {
4275 mips_load_const (code, mips_at, ins->inst_offset);
4276 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
4277 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4278 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4280 break;
4281 case OP_STORER4_MEMBASE_REG:
4282 g_assert (mips_is_imm16 (ins->inst_offset));
4283 #if PROMOTE_R4_TO_R8
4284 /* Need to convert ins->sreg1 to single-precision first */
4285 mips_cvtsd (code, mips_ftemp, ins->sreg1);
4286 mips_swc1 (code, mips_ftemp, ins->inst_destbasereg, ins->inst_offset);
4287 #else
4288 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4289 #endif
4290 break;
4291 case OP_MIPS_LWC1:
4292 g_assert (mips_is_imm16 (ins->inst_offset));
4293 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4294 break;
4295 case OP_LOADR4_MEMBASE:
4296 g_assert (mips_is_imm16 (ins->inst_offset));
4297 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4298 #if PROMOTE_R4_TO_R8
4299 /* Convert to double precision in place */
4300 mips_cvtds (code, ins->dreg, ins->dreg);
4301 #endif
4302 break;
4303 case OP_LOADR4_MEMINDEX:
4304 mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4305 mips_lwc1 (code, ins->dreg, mips_at, 0);
4306 break;
4307 case OP_LOADR8_MEMINDEX:
4308 mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4309 #if _MIPS_SIM == _ABIO32
4310 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4311 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4312 #elif _MIPS_SIM == _ABIN32
4313 mips_ldc1 (code, ins->dreg, mips_at, 0);
4314 #endif
4315 break;
4316 case OP_STORER4_MEMINDEX:
4317 mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4318 #if PROMOTE_R4_TO_R8
4319 /* Need to convert ins->sreg1 to single-precision first */
4320 mips_cvtsd (code, mips_ftemp, ins->sreg1);
4321 mips_swc1 (code, mips_ftemp, mips_at, 0);
4322 #else
4323 mips_swc1 (code, ins->sreg1, mips_at, 0);
4324 #endif
4325 break;
4326 case OP_STORER8_MEMINDEX:
4327 mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4328 #if _MIPS_SIM == _ABIO32
4329 mips_swc1 (code, ins->sreg1, mips_at, ls_word_offset);
4330 mips_swc1 (code, ins->sreg1+1, mips_at, ms_word_offset);
4331 #elif _MIPS_SIM == _ABIN32
4332 mips_sdc1 (code, ins->sreg1, mips_at, 0);
4333 #endif
4334 break;
4335 case OP_ICONV_TO_R_UN: {
4336 static const guint64 adjust_val = 0x41F0000000000000ULL;
4338 /* convert unsigned int to double */
4339 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4340 mips_bgez (code, ins->sreg1, 5);
4341 mips_cvtdw (code, ins->dreg, mips_ftemp);
4343 mips_load (code, mips_at, (guint32) &adjust_val);
4344 mips_ldc1 (code, mips_ftemp, mips_at, 0);
4345 mips_faddd (code, ins->dreg, ins->dreg, mips_ftemp);
4346 /* target is here */
4347 break;
4349 case OP_ICONV_TO_R4:
4350 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4351 mips_cvtsw (code, ins->dreg, mips_ftemp);
4352 mips_cvtds (code, ins->dreg, ins->dreg);
4353 break;
4354 case OP_ICONV_TO_R8:
4355 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4356 mips_cvtdw (code, ins->dreg, mips_ftemp);
4357 break;
4358 case OP_FCONV_TO_I1:
4359 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4360 break;
4361 case OP_FCONV_TO_U1:
4362 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4363 break;
4364 case OP_FCONV_TO_I2:
4365 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4366 break;
4367 case OP_FCONV_TO_U2:
4368 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4369 break;
4370 case OP_FCONV_TO_I4:
4371 case OP_FCONV_TO_I:
4372 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4373 break;
4374 case OP_FCONV_TO_U4:
4375 case OP_FCONV_TO_U:
4376 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4377 break;
4378 case OP_SQRT:
4379 mips_fsqrtd (code, ins->dreg, ins->sreg1);
4380 break;
4381 case OP_FADD:
4382 mips_faddd (code, ins->dreg, ins->sreg1, ins->sreg2);
4383 break;
4384 case OP_FSUB:
4385 mips_fsubd (code, ins->dreg, ins->sreg1, ins->sreg2);
4386 break;
4387 case OP_FMUL:
4388 mips_fmuld (code, ins->dreg, ins->sreg1, ins->sreg2);
4389 break;
4390 case OP_FDIV:
4391 mips_fdivd (code, ins->dreg, ins->sreg1, ins->sreg2);
4392 break;
4393 case OP_FNEG:
4394 mips_fnegd (code, ins->dreg, ins->sreg1);
4395 break;
4396 case OP_FCEQ:
4397 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
4398 mips_addiu (code, ins->dreg, mips_zero, 1);
4399 mips_fbtrue (code, 2);
4400 mips_nop (code);
4401 MIPS_MOVE (code, ins->dreg, mips_zero);
4402 break;
4403 case OP_FCLT:
4404 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
4405 mips_addiu (code, ins->dreg, mips_zero, 1);
4406 mips_fbtrue (code, 2);
4407 mips_nop (code);
4408 MIPS_MOVE (code, ins->dreg, mips_zero);
4409 break;
4410 case OP_FCLT_UN:
4411 /* Less than, or Unordered */
4412 mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
4413 mips_addiu (code, ins->dreg, mips_zero, 1);
4414 mips_fbtrue (code, 2);
4415 mips_nop (code);
4416 MIPS_MOVE (code, ins->dreg, mips_zero);
4417 break;
4418 case OP_FCGT:
4419 mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
4420 MIPS_MOVE (code, ins->dreg, mips_zero);
4421 mips_fbtrue (code, 2);
4422 mips_nop (code);
4423 mips_addiu (code, ins->dreg, mips_zero, 1);
4424 break;
4425 case OP_FCGT_UN:
4426 /* Greater than, or Unordered */
4427 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
4428 MIPS_MOVE (code, ins->dreg, mips_zero);
4429 mips_fbtrue (code, 2);
4430 mips_nop (code);
4431 mips_addiu (code, ins->dreg, mips_zero, 1);
4432 break;
4433 case OP_MIPS_FBEQ:
4434 case OP_MIPS_FBNE:
4435 case OP_MIPS_FBLT:
4436 case OP_MIPS_FBLT_UN:
4437 case OP_MIPS_FBGT:
4438 case OP_MIPS_FBGT_UN:
4439 case OP_MIPS_FBGE:
4440 case OP_MIPS_FBGE_UN:
4441 case OP_MIPS_FBLE:
4442 case OP_MIPS_FBLE_UN: {
4443 int cond = 0;
4444 gboolean is_true = TRUE, is_ordered = FALSE;
4445 guint32 *buf = NULL;
4447 switch (ins->opcode) {
4448 case OP_MIPS_FBEQ:
4449 cond = MIPS_FPU_EQ;
4450 is_true = TRUE;
4451 break;
4452 case OP_MIPS_FBNE:
4453 cond = MIPS_FPU_EQ;
4454 is_true = FALSE;
4455 break;
4456 case OP_MIPS_FBLT:
4457 cond = MIPS_FPU_LT;
4458 is_true = TRUE;
4459 is_ordered = TRUE;
4460 break;
4461 case OP_MIPS_FBLT_UN:
4462 cond = MIPS_FPU_ULT;
4463 is_true = TRUE;
4464 break;
4465 case OP_MIPS_FBGT:
4466 cond = MIPS_FPU_LE;
4467 is_true = FALSE;
4468 is_ordered = TRUE;
4469 break;
4470 case OP_MIPS_FBGT_UN:
4471 cond = MIPS_FPU_OLE;
4472 is_true = FALSE;
4473 break;
4474 case OP_MIPS_FBGE:
4475 cond = MIPS_FPU_LT;
4476 is_true = FALSE;
4477 is_ordered = TRUE;
4478 break;
4479 case OP_MIPS_FBGE_UN:
4480 cond = MIPS_FPU_OLT;
4481 is_true = FALSE;
4482 break;
4483 case OP_MIPS_FBLE:
4484 cond = MIPS_FPU_OLE;
4485 is_true = TRUE;
4486 is_ordered = TRUE;
4487 break;
4488 case OP_MIPS_FBLE_UN:
4489 cond = MIPS_FPU_ULE;
4490 is_true = TRUE;
4491 break;
4492 default:
4493 g_assert_not_reached ();
4496 if (is_ordered) {
4497 /* Skip the check if unordered */
4498 mips_fcmpd (code, MIPS_FPU_UN, ins->sreg1, ins->sreg2);
4499 mips_nop (code);
4500 buf = (guint32*)code;
4501 mips_fbtrue (code, 0);
4502 mips_nop (code);
4505 mips_fcmpd (code, cond, ins->sreg1, ins->sreg2);
4506 mips_nop (code);
4507 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4508 if (is_true)
4509 mips_fbtrue (code, 0);
4510 else
4511 mips_fbfalse (code, 0);
4512 mips_nop (code);
4514 if (is_ordered)
4515 mips_patch (buf, (guint32)code);
4516 break;
4518 case OP_CKFINITE: {
4519 guint32 *branch_patch;
4521 mips_mfc1 (code, mips_at, ins->sreg1+1);
4522 mips_srl (code, mips_at, mips_at, 16+4);
4523 mips_andi (code, mips_at, mips_at, 2047);
4524 mips_addiu (code, mips_at, mips_at, -2047);
4526 branch_patch = (guint32 *)(void *)code;
4527 mips_bne (code, mips_at, mips_zero, 0);
4528 mips_nop (code);
4530 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
4531 mips_patch (branch_patch, (guint32)code);
4532 mips_fmovd (code, ins->dreg, ins->sreg1);
4533 break;
4535 case OP_JUMP_TABLE:
4536 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
4537 mips_load (code, ins->dreg, 0x0f0f0f0f);
4538 break;
4539 case OP_GC_SAFE_POINT:
4540 break;
4543 default:
4544 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4545 g_assert_not_reached ();
4548 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4549 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
4550 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
4551 g_assert_not_reached ();
4554 cpos += max_len;
4556 last_ins = ins;
4557 last_offset = offset;
4560 cfg->code_len = code - cfg->native_code;
4563 void
4564 mono_arch_register_lowlevel_calls (void)
4568 void
4569 mono_arch_patch_code (MonoCompile *cfg, MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors, MonoError *error)
4571 MonoJumpInfo *patch_info;
4573 mono_error_init (error);
4575 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4576 unsigned char *ip = patch_info->ip.i + code;
4577 const unsigned char *target = NULL;
4579 switch (patch_info->type) {
4580 case MONO_PATCH_INFO_IP:
4581 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)ip);
4582 continue;
4583 case MONO_PATCH_INFO_SWITCH: {
4584 gpointer *table = (gpointer *)patch_info->data.table->table;
4585 int i;
4587 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)table);
4589 for (i = 0; i < patch_info->data.table->table_size; i++) {
4590 table [i] = (int)patch_info->data.table->table [i] + code;
4592 continue;
4594 case MONO_PATCH_INFO_METHODCONST:
4595 case MONO_PATCH_INFO_CLASS:
4596 case MONO_PATCH_INFO_IMAGE:
4597 case MONO_PATCH_INFO_FIELD:
4598 case MONO_PATCH_INFO_VTABLE:
4599 case MONO_PATCH_INFO_IID:
4600 case MONO_PATCH_INFO_SFLDA:
4601 case MONO_PATCH_INFO_LDSTR:
4602 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4603 case MONO_PATCH_INFO_LDTOKEN:
4604 case MONO_PATCH_INFO_R4:
4605 case MONO_PATCH_INFO_R8:
4606 /* from OP_AOTCONST : lui + addiu */
4607 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors, error);
4608 return_if_nok (error);
4610 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)target);
4611 continue;
4612 #if 0
4613 case MONO_PATCH_INFO_EXC_NAME:
4614 g_assert_not_reached ();
4615 *((gconstpointer *)(void *)(ip + 1)) = patch_info->data.name;
4616 continue;
4617 #endif
4618 case MONO_PATCH_INFO_NONE:
4619 /* everything is dealt with at epilog output time */
4620 continue;
4621 default:
4622 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors, error);
4623 return_if_nok (error);
4625 mips_patch ((guint32 *)(void *)ip, (guint32)target);
4626 break;
4632 * Allow tracing to work with this interface (with an optional argument)
4634 * This code is expected to be inserted just after the 'real' prolog code,
4635 * and before the first basic block. We need to allocate a 2nd, temporary
4636 * stack frame so that we can preserve f12-f15 as well as a0-a3.
4639 void*
4640 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4642 guchar *code = p;
4643 int offset = cfg->arch.tracing_offset;
4645 mips_nop (code);
4646 mips_nop (code);
4647 mips_nop (code);
4649 MIPS_SW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4650 MIPS_SW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4651 MIPS_SW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4652 MIPS_SW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4653 #if _MIPS_SIM == _ABIN32
4654 NOT_IMPLEMENTED;
4655 /* FIXME: Need a separate region for these */
4656 MIPS_SW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4657 MIPS_SW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4658 MIPS_SW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4659 MIPS_SW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4661 #endif
4663 mips_load_const (code, mips_a0, cfg->method);
4664 mips_addiu (code, mips_a1, mips_sp, offset);
4665 mips_call (code, mips_t9, func);
4666 mips_nop (code);
4668 MIPS_LW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4669 MIPS_LW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4670 MIPS_LW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4671 MIPS_LW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4672 #if _MIPS_SIM == _ABIN32
4673 NOT_IMPLEMENTED;
4675 MIPS_LW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4676 MIPS_LW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4677 MIPS_LW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4678 MIPS_LW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4680 #endif
4682 mips_nop (code);
4683 mips_nop (code);
4684 mips_nop (code);
4685 return code;
4688 void
4689 mips_adjust_stackframe(MonoCompile *cfg)
4691 MonoBasicBlock *bb;
4692 int delta, threshold, i;
4693 MonoMethodSignature *sig;
4694 int ra_offset;
4696 if (cfg->stack_offset == cfg->arch.local_alloc_offset)
4697 return;
4699 /* adjust cfg->stack_offset for account for down-spilling */
4700 cfg->stack_offset += SIZEOF_REGISTER;
4702 /* re-align cfg->stack_offset if needed (due to var spilling) */
4703 cfg->stack_offset = (cfg->stack_offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
4704 delta = cfg->stack_offset - cfg->arch.local_alloc_offset;
4705 if (cfg->verbose_level > 2) {
4706 g_print ("mips_adjust_stackframe:\n");
4707 g_print ("\tspillvars allocated 0x%x -> 0x%x\n", cfg->arch.local_alloc_offset, cfg->stack_offset);
4709 threshold = cfg->arch.local_alloc_offset;
4710 ra_offset = cfg->stack_offset - sizeof(gpointer);
4711 if (cfg->verbose_level > 2) {
4712 g_print ("\tra_offset %d/0x%x delta %d/0x%x\n", ra_offset, ra_offset, delta, delta);
4715 sig = mono_method_signature (cfg->method);
4716 if (sig && sig->ret && MONO_TYPE_ISSTRUCT (sig->ret)) {
4717 cfg->vret_addr->inst_offset += delta;
4719 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4720 MonoInst *inst = cfg->args [i];
4722 inst->inst_offset += delta;
4726 * loads and stores based off the frame reg that (used to) lie
4727 * above the spill var area need to be increased by 'delta'
4728 * to make room for the spill vars.
4730 /* Need to find loads and stores to adjust that
4731 * are above where the spillvars were inserted, but
4732 * which are not the spillvar references themselves.
4734 * Idea - since all offsets from fp are positive, make
4735 * spillvar offsets negative to begin with so we can spot
4736 * them here.
4739 #if 1
4740 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4741 int ins_cnt = 0;
4742 MonoInst *ins;
4744 if (cfg->verbose_level > 2) {
4745 g_print ("BASIC BLOCK %d:\n", bb->block_num);
4747 MONO_BB_FOR_EACH_INS (bb, ins) {
4748 int adj_c0 = 0;
4749 int adj_imm = 0;
4751 if (cfg->verbose_level > 2) {
4752 mono_print_ins_index (ins_cnt, ins);
4754 /* The == mips_sp tests catch FP spills */
4755 if (MONO_IS_LOAD_MEMBASE(ins) && ((ins->inst_basereg == mips_fp) ||
4756 (ins->inst_basereg == mips_sp))) {
4757 switch (ins->opcode) {
4758 case OP_LOADI8_MEMBASE:
4759 case OP_LOADR8_MEMBASE:
4760 adj_c0 = 8;
4761 break;
4762 default:
4763 adj_c0 = 4;
4764 break;
4766 } else if (MONO_IS_STORE_MEMBASE(ins) && ((ins->dreg == mips_fp) ||
4767 (ins->dreg == mips_sp))) {
4768 switch (ins->opcode) {
4769 case OP_STOREI8_MEMBASE_REG:
4770 case OP_STORER8_MEMBASE_REG:
4771 case OP_STOREI8_MEMBASE_IMM:
4772 adj_c0 = 8;
4773 break;
4774 default:
4775 adj_c0 = 4;
4776 break;
4779 if (((ins->opcode == OP_ADD_IMM) || (ins->opcode == OP_IADD_IMM)) && (ins->sreg1 == cfg->frame_reg))
4780 adj_imm = 1;
4781 if (adj_c0) {
4782 if (ins->inst_c0 >= threshold) {
4783 ins->inst_c0 += delta;
4784 if (cfg->verbose_level > 2) {
4785 g_print ("adj");
4786 mono_print_ins_index (ins_cnt, ins);
4789 else if (ins->inst_c0 < 0) {
4790 /* Adj_c0 holds the size of the datatype. */
4791 ins->inst_c0 = - ins->inst_c0 - adj_c0;
4792 if (cfg->verbose_level > 2) {
4793 g_print ("spill");
4794 mono_print_ins_index (ins_cnt, ins);
4797 g_assert (ins->inst_c0 != ra_offset);
4799 if (adj_imm) {
4800 if (ins->inst_imm >= threshold) {
4801 ins->inst_imm += delta;
4802 if (cfg->verbose_level > 2) {
4803 g_print ("adj");
4804 mono_print_ins_index (ins_cnt, ins);
4807 g_assert (ins->inst_c0 != ra_offset);
4810 ++ins_cnt;
4813 #endif
4817 * Stack frame layout:
4819 * ------------------- sp + cfg->stack_usage + cfg->param_area
4820 * param area incoming
4821 * ------------------- sp + cfg->stack_usage + MIPS_STACK_PARAM_OFFSET
4822 * a0-a3 incoming
4823 * ------------------- sp + cfg->stack_usage
4824 * ra
4825 * ------------------- sp + cfg->stack_usage-4
4826 * spilled regs
4827 * ------------------- sp +
4828 * MonoLMF structure optional
4829 * ------------------- sp + cfg->arch.lmf_offset
4830 * saved registers s0-s8
4831 * ------------------- sp + cfg->arch.iregs_offset
4832 * locals
4833 * ------------------- sp + cfg->param_area
4834 * param area outgoing
4835 * ------------------- sp + MIPS_STACK_PARAM_OFFSET
4836 * a0-a3 outgoing
4837 * ------------------- sp
4838 * red zone
4840 guint8 *
4841 mono_arch_emit_prolog (MonoCompile *cfg)
4843 MonoMethod *method = cfg->method;
4844 MonoMethodSignature *sig;
4845 MonoInst *inst;
4846 int alloc_size, pos, i, max_offset;
4847 int alloc2_size = 0;
4848 guint8 *code;
4849 CallInfo *cinfo;
4850 int tracing = 0;
4851 guint32 iregs_to_save = 0;
4852 #if SAVE_FP_REGS
4853 guint32 fregs_to_save = 0;
4854 #endif
4855 /* lmf_offset is the offset of the LMF from our stack pointer. */
4856 guint32 lmf_offset = cfg->arch.lmf_offset;
4857 int cfa_offset = 0;
4858 MonoBasicBlock *bb;
4860 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4861 tracing = 1;
4863 if (tracing)
4864 cfg->flags |= MONO_CFG_HAS_CALLS;
4866 sig = mono_method_signature (method);
4867 cfg->code_size = 768 + sig->param_count * 20;
4868 code = cfg->native_code = g_malloc (cfg->code_size);
4871 * compute max_offset in order to use short forward jumps.
4873 max_offset = 0;
4874 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4875 MonoInst *ins = bb->code;
4876 bb->max_offset = max_offset;
4878 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
4879 max_offset += 6;
4881 MONO_BB_FOR_EACH_INS (bb, ins)
4882 max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
4884 if (max_offset > 0xffff)
4885 cfg->arch.long_branch = TRUE;
4888 * Currently, fp points to the bottom of the frame on MIPS, unlike other platforms.
4889 * This means that we have to adjust the offsets inside instructions which reference
4890 * arguments received on the stack, since the initial offset doesn't take into
4891 * account spill slots.
4893 mips_adjust_stackframe (cfg);
4895 /* Offset between current sp and the CFA */
4896 cfa_offset = 0;
4897 mono_emit_unwind_op_def_cfa (cfg, code, mips_sp, cfa_offset);
4899 /* stack_offset should not be changed here. */
4900 alloc_size = cfg->stack_offset;
4901 cfg->stack_usage = alloc_size;
4903 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
4904 #if SAVE_FP_REGS
4905 #if 0
4906 fregs_to_save = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
4907 #else
4908 fregs_to_save = MONO_ARCH_CALLEE_SAVED_FREGS;
4909 fregs_to_save |= (fregs_to_save << 1);
4910 #endif
4911 #endif
4912 /* If the stack size is too big, save 1024 bytes to start with
4913 * so the prologue can use imm16(reg) addressing, then allocate
4914 * the rest of the frame.
4916 if (alloc_size > ((1 << 15) - 1024)) {
4917 alloc2_size = alloc_size - 1024;
4918 alloc_size = 1024;
4920 if (alloc_size) {
4921 g_assert (mips_is_imm16 (-alloc_size));
4922 mips_addiu (code, mips_sp, mips_sp, -alloc_size);
4923 cfa_offset = alloc_size;
4924 mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
4927 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
4928 int offset = alloc_size + MIPS_RET_ADDR_OFFSET;
4929 if (mips_is_imm16(offset))
4930 mips_sw (code, mips_ra, mips_sp, offset);
4931 else {
4932 g_assert_not_reached ();
4934 /* sp = cfa - cfa_offset, so sp + offset = cfa - cfa_offset + offset */
4935 mono_emit_unwind_op_offset (cfg, code, mips_ra, offset - cfa_offset);
4938 /* XXX - optimize this later to not save all regs if LMF constructed */
4939 pos = cfg->arch.iregs_offset - alloc2_size;
4941 if (iregs_to_save) {
4942 /* save used registers in own stack frame (at pos) */
4943 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
4944 if (iregs_to_save & (1 << i)) {
4945 g_assert (pos < (int)(cfg->stack_usage - sizeof(gpointer)));
4946 g_assert (mips_is_imm16(pos));
4947 MIPS_SW (code, i, mips_sp, pos);
4948 mono_emit_unwind_op_offset (cfg, code, i, pos - cfa_offset);
4949 pos += SIZEOF_REGISTER;
4954 // FIXME: Don't save registers twice if there is an LMF
4955 // s8 has to be special cased since it is overwritten with the updated value
4956 // below
4957 if (method->save_lmf) {
4958 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
4959 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[i]);
4960 g_assert (mips_is_imm16(offset));
4961 if (MIPS_LMF_IREGMASK & (1 << i))
4962 MIPS_SW (code, i, mips_sp, offset);
4966 #if SAVE_FP_REGS
4967 /* Save float registers */
4968 if (fregs_to_save) {
4969 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
4970 if (fregs_to_save & (1 << i)) {
4971 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
4972 g_assert (mips_is_imm16(pos));
4973 mips_swc1 (code, i, mips_sp, pos);
4974 pos += sizeof (gulong);
4979 if (method->save_lmf) {
4980 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
4981 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, fregs[i]);
4982 g_assert (mips_is_imm16(offset));
4983 mips_swc1 (code, i, mips_sp, offset);
4987 #endif
4988 if (cfg->frame_reg != mips_sp) {
4989 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
4990 mono_emit_unwind_op_def_cfa (cfg, code, cfg->frame_reg, cfa_offset);
4992 if (method->save_lmf) {
4993 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[cfg->frame_reg]);
4994 g_assert (mips_is_imm16(offset));
4995 MIPS_SW (code, cfg->frame_reg, mips_sp, offset);
4999 /* store runtime generic context */
5000 if (cfg->rgctx_var) {
5001 MonoInst *ins = cfg->rgctx_var;
5003 g_assert (ins->opcode == OP_REGOFFSET);
5005 g_assert (mips_is_imm16 (ins->inst_offset));
5006 mips_sw (code, MONO_ARCH_RGCTX_REG, ins->inst_basereg, ins->inst_offset);
5009 /* load arguments allocated to register from the stack */
5010 pos = 0;
5012 if (!cfg->arch.cinfo)
5013 cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
5014 cinfo = cfg->arch.cinfo;
5016 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
5017 ArgInfo *ainfo = &cinfo->ret;
5018 inst = cfg->vret_addr;
5019 if (inst->opcode == OP_REGVAR)
5020 MIPS_MOVE (code, inst->dreg, ainfo->reg);
5021 else if (mips_is_imm16 (inst->inst_offset)) {
5022 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5023 } else {
5024 mips_load_const (code, mips_at, inst->inst_offset);
5025 mips_addu (code, mips_at, mips_at, inst->inst_basereg);
5026 mips_sw (code, ainfo->reg, mips_at, 0);
5030 if (sig->call_convention == MONO_CALL_VARARG) {
5031 ArgInfo *cookie = &cinfo->sig_cookie;
5032 int offset = alloc_size + cookie->offset;
5034 /* Save the sig cookie address */
5035 g_assert (cookie->storage == ArgOnStack);
5037 g_assert (mips_is_imm16(offset));
5038 mips_addi (code, mips_at, cfg->frame_reg, offset);
5039 mips_sw (code, mips_at, cfg->frame_reg, cfg->sig_cookie - alloc2_size);
5042 /* Keep this in sync with emit_load_volatile_arguments */
5043 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
5044 ArgInfo *ainfo = cinfo->args + i;
5045 inst = cfg->args [pos];
5047 if (cfg->verbose_level > 2)
5048 g_print ("Saving argument %d (type: %d)\n", i, ainfo->storage);
5049 if (inst->opcode == OP_REGVAR) {
5050 /* Argument ends up in a register */
5051 if (ainfo->storage == ArgInIReg)
5052 MIPS_MOVE (code, inst->dreg, ainfo->reg);
5053 else if (ainfo->storage == ArgInFReg) {
5054 g_assert_not_reached();
5055 #if 0
5056 ppc_fmr (code, inst->dreg, ainfo->reg);
5057 #endif
5059 else if (ainfo->storage == ArgOnStack) {
5060 int offset = cfg->stack_usage + ainfo->offset;
5061 g_assert (mips_is_imm16(offset));
5062 mips_lw (code, inst->dreg, mips_sp, offset);
5063 } else
5064 g_assert_not_reached ();
5066 if (cfg->verbose_level > 2)
5067 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
5068 } else {
5069 /* Argument ends up on the stack */
5070 if (ainfo->storage == ArgInIReg) {
5071 int basereg_offset;
5072 /* Incoming parameters should be above this frame */
5073 if (cfg->verbose_level > 2)
5074 g_print ("stack slot at %d of %d+%d\n",
5075 inst->inst_offset, alloc_size, alloc2_size);
5076 /* g_assert (inst->inst_offset >= alloc_size); */
5077 g_assert (inst->inst_basereg == cfg->frame_reg);
5078 basereg_offset = inst->inst_offset - alloc2_size;
5079 g_assert (mips_is_imm16 (basereg_offset));
5080 switch (ainfo->size) {
5081 case 1:
5082 mips_sb (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5083 break;
5084 case 2:
5085 mips_sh (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5086 break;
5087 case 0: /* XXX */
5088 case 4:
5089 mips_sw (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5090 break;
5091 case 8:
5092 #if (SIZEOF_REGISTER == 4)
5093 mips_sw (code, ainfo->reg, inst->inst_basereg, basereg_offset + ls_word_offset);
5094 mips_sw (code, ainfo->reg + 1, inst->inst_basereg, basereg_offset + ms_word_offset);
5095 #elif (SIZEOF_REGISTER == 8)
5096 mips_sd (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5097 #endif
5098 break;
5099 default:
5100 g_assert_not_reached ();
5101 break;
5103 } else if (ainfo->storage == ArgOnStack) {
5105 * Argument comes in on the stack, and ends up on the stack
5106 * 1 and 2 byte args are passed as 32-bit quantities, but used as
5107 * 8 and 16 bit quantities. Shorten them in place.
5109 g_assert (mips_is_imm16 (inst->inst_offset));
5110 switch (ainfo->size) {
5111 case 1:
5112 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
5113 mips_sb (code, mips_at, inst->inst_basereg, inst->inst_offset);
5114 break;
5115 case 2:
5116 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
5117 mips_sh (code, mips_at, inst->inst_basereg, inst->inst_offset);
5118 break;
5119 case 0: /* XXX */
5120 case 4:
5121 case 8:
5122 break;
5123 default:
5124 g_assert_not_reached ();
5126 } else if (ainfo->storage == ArgInFReg) {
5127 g_assert (mips_is_imm16 (inst->inst_offset));
5128 g_assert (mips_is_imm16 (inst->inst_offset+4));
5129 if (ainfo->size == 8) {
5130 #if _MIPS_SIM == _ABIO32
5131 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
5132 mips_swc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
5133 #elif _MIPS_SIM == _ABIN32
5134 mips_sdc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5135 #endif
5137 else if (ainfo->size == 4)
5138 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5139 else
5140 g_assert_not_reached ();
5141 } else if (ainfo->storage == ArgStructByVal) {
5142 int i;
5143 int doffset = inst->inst_offset;
5145 g_assert (mips_is_imm16 (inst->inst_offset));
5146 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
5147 /* Push the argument registers into their stack slots */
5148 for (i = 0; i < ainfo->size; ++i) {
5149 g_assert (mips_is_imm16(doffset));
5150 MIPS_SW (code, ainfo->reg + i, inst->inst_basereg, doffset);
5151 doffset += SIZEOF_REGISTER;
5153 } else if (ainfo->storage == ArgStructByAddr) {
5154 g_assert (mips_is_imm16 (inst->inst_offset));
5155 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
5156 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
5157 } else
5158 g_assert_not_reached ();
5160 pos++;
5163 if (method->save_lmf) {
5164 mips_load_const (code, mips_at, MIPS_LMF_MAGIC1);
5165 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, magic));
5167 if (lmf_pthread_key != -1) {
5168 g_assert_not_reached();
5169 #if 0
5170 emit_tls_access (code, mips_temp, lmf_pthread_key);
5171 #endif
5172 if (G_STRUCT_OFFSET (MonoJitTlsData, lmf)) {
5173 int offset = G_STRUCT_OFFSET (MonoJitTlsData, lmf);
5174 g_assert (mips_is_imm16(offset));
5175 mips_addiu (code, mips_a0, mips_temp, offset);
5177 } else {
5178 /* This can/will clobber the a0-a3 registers */
5179 mips_call (code, mips_t9, (gpointer)mono_get_lmf_addr);
5182 /* mips_v0 is the result from mono_get_lmf_addr () (MonoLMF **) */
5183 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5184 mips_sw (code, mips_v0, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5185 /* new_lmf->previous_lmf = *lmf_addr */
5186 mips_lw (code, mips_at, mips_v0, 0);
5187 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5188 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5189 /* *(lmf_addr) = sp + lmf_offset */
5190 g_assert (mips_is_imm16(lmf_offset));
5191 mips_addiu (code, mips_at, mips_sp, lmf_offset);
5192 mips_sw (code, mips_at, mips_v0, 0);
5194 /* save method info */
5195 mips_load_const (code, mips_at, method);
5196 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, method)));
5197 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, method));
5199 /* save the current IP */
5200 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5201 mips_load_const (code, mips_at, 0x01010101);
5202 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, eip));
5205 if (alloc2_size) {
5206 if (mips_is_imm16 (-alloc2_size)) {
5207 mips_addu (code, mips_sp, mips_sp, -alloc2_size);
5209 else {
5210 mips_load_const (code, mips_at, -alloc2_size);
5211 mips_addu (code, mips_sp, mips_sp, mips_at);
5213 alloc_size += alloc2_size;
5214 cfa_offset += alloc2_size;
5215 if (cfg->frame_reg != mips_sp)
5216 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
5217 else
5218 mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
5221 if (tracing) {
5222 #if _MIPS_SIM == _ABIO32
5223 cfg->arch.tracing_offset = cfg->stack_offset;
5224 #elif _MIPS_SIM == _ABIN32
5225 /* no stack slots by default for argument regs, reserve a special block */
5226 g_assert_not_reached ();
5227 #endif
5228 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
5231 cfg->code_len = code - cfg->native_code;
5232 g_assert (cfg->code_len < cfg->code_size);
5234 return code;
5237 enum {
5238 SAVE_NONE,
5239 SAVE_STRUCT,
5240 SAVE_ONE,
5241 SAVE_TWO,
5242 SAVE_FP
5245 void*
5246 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
5248 guchar *code = p;
5249 int save_mode = SAVE_NONE;
5250 int offset;
5251 MonoMethod *method = cfg->method;
5252 int rtype = mini_get_underlying_type (mono_method_signature (method)->ret)->type;
5253 int save_offset = MIPS_STACK_PARAM_OFFSET;
5255 g_assert ((save_offset & (MIPS_STACK_ALIGNMENT-1)) == 0);
5257 offset = code - cfg->native_code;
5258 /* we need about 16 instructions */
5259 if (offset > (cfg->code_size - 16 * 4)) {
5260 cfg->code_size *= 2;
5261 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5262 code = cfg->native_code + offset;
5264 mips_nop (code);
5265 mips_nop (code);
5266 switch (rtype) {
5267 case MONO_TYPE_VOID:
5268 /* special case string .ctor icall */
5269 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
5270 save_mode = SAVE_ONE;
5271 else
5272 save_mode = SAVE_NONE;
5273 break;
5274 case MONO_TYPE_R4:
5275 case MONO_TYPE_R8:
5276 save_mode = SAVE_FP;
5277 break;
5278 case MONO_TYPE_VALUETYPE:
5279 save_mode = SAVE_STRUCT;
5280 break;
5281 case MONO_TYPE_I8:
5282 case MONO_TYPE_U8:
5283 #if SIZEOF_REGISTER == 4
5284 save_mode = SAVE_TWO;
5285 #elif SIZEOF_REGISTER == 8
5286 save_mode = SAVE_ONE;
5287 #endif
5288 break;
5289 default:
5290 save_mode = SAVE_ONE;
5291 break;
5294 mips_addiu (code, mips_sp, mips_sp, -32);
5295 g_assert (mips_is_imm16(save_offset));
5296 switch (save_mode) {
5297 case SAVE_TWO:
5298 mips_sw (code, mips_v0, mips_sp, save_offset);
5299 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5300 mips_sw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5301 if (enable_arguments) {
5302 MIPS_MOVE (code, mips_a1, mips_v0);
5303 MIPS_MOVE (code, mips_a2, mips_v1);
5305 break;
5306 case SAVE_ONE:
5307 MIPS_SW (code, mips_v0, mips_sp, save_offset);
5308 if (enable_arguments) {
5309 MIPS_MOVE (code, mips_a1, mips_v0);
5311 break;
5312 case SAVE_FP:
5313 mips_sdc1 (code, mips_f0, mips_sp, save_offset);
5314 mips_ldc1 (code, mips_f12, mips_sp, save_offset);
5315 mips_lw (code, mips_a0, mips_sp, save_offset);
5316 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5317 mips_lw (code, mips_a1, mips_sp, save_offset + SIZEOF_REGISTER);
5318 break;
5319 case SAVE_STRUCT:
5320 case SAVE_NONE:
5321 default:
5322 break;
5324 mips_load_const (code, mips_a0, cfg->method);
5325 mips_call (code, mips_t9, func);
5327 switch (save_mode) {
5328 case SAVE_TWO:
5329 mips_lw (code, mips_v0, mips_sp, save_offset);
5330 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5331 mips_lw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5332 break;
5333 case SAVE_ONE:
5334 MIPS_LW (code, mips_v0, mips_sp, save_offset);
5335 break;
5336 case SAVE_FP:
5337 mips_ldc1 (code, mips_f0, mips_sp, save_offset);
5338 break;
5339 case SAVE_STRUCT:
5340 case SAVE_NONE:
5341 default:
5342 break;
5344 mips_addiu (code, mips_sp, mips_sp, 32);
5345 mips_nop (code);
5346 mips_nop (code);
5347 return code;
5350 guint8 *
5351 mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code)
5353 MonoMethod *method = cfg->method;
5354 int pos = 0, i;
5355 int max_epilog_size = 16 + 20*4;
5356 int alloc2_size = 0;
5357 guint32 iregs_to_restore;
5358 #if SAVE_FP_REGS
5359 guint32 fregs_to_restore;
5360 #endif
5362 if (cfg->method->save_lmf)
5363 max_epilog_size += 128;
5365 if (mono_jit_trace_calls != NULL)
5366 max_epilog_size += 50;
5368 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5369 max_epilog_size += 50;
5371 if (code)
5372 pos = code - cfg->native_code;
5373 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5374 cfg->code_size *= 2;
5375 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5376 cfg->stat_code_reallocs++;
5380 * Keep in sync with OP_JMP
5382 if (code)
5383 code = cfg->native_code + pos;
5384 else
5385 code = cfg->native_code + cfg->code_len;
5387 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5388 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5390 if (cfg->frame_reg != mips_sp) {
5391 MIPS_MOVE (code, mips_sp, cfg->frame_reg);
5393 /* If the stack frame is really large, deconstruct it in two steps */
5394 if (cfg->stack_usage > ((1 << 15) - 1024)) {
5395 alloc2_size = cfg->stack_usage - 1024;
5396 /* partially deconstruct the stack */
5397 mips_load_const (code, mips_at, alloc2_size);
5398 mips_addu (code, mips_sp, mips_sp, mips_at);
5400 pos = cfg->arch.iregs_offset - alloc2_size;
5401 iregs_to_restore = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
5402 if (iregs_to_restore) {
5403 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5404 if (iregs_to_restore & (1 << i)) {
5405 g_assert (mips_is_imm16(pos));
5406 MIPS_LW (code, i, mips_sp, pos);
5407 pos += SIZEOF_REGISTER;
5412 #if SAVE_FP_REGS
5413 #if 0
5414 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
5415 #else
5416 fregs_to_restore = MONO_ARCH_CALLEE_SAVED_FREGS;
5417 fregs_to_restore |= (fregs_to_restore << 1);
5418 #endif
5419 if (fregs_to_restore) {
5420 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5421 if (fregs_to_restore & (1 << i)) {
5422 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
5423 g_assert (mips_is_imm16(pos));
5424 mips_lwc1 (code, i, mips_sp, pos);
5425 pos += FREG_SIZE
5429 #endif
5431 /* Unlink the LMF if necessary */
5432 if (method->save_lmf) {
5433 int lmf_offset = cfg->arch.lmf_offset;
5435 /* t0 = current_lmf->previous_lmf */
5436 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5437 mips_lw (code, mips_temp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5438 /* t1 = lmf_addr */
5439 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5440 mips_lw (code, mips_t1, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5441 /* (*lmf_addr) = previous_lmf */
5442 mips_sw (code, mips_temp, mips_t1, 0);
5445 #if 0
5446 /* Restore the fp */
5447 mips_lw (code, mips_fp, mips_sp, cfg->stack_usage + MIPS_FP_ADDR_OFFSET);
5448 #endif
5449 /* Restore ra */
5450 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
5451 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET));
5452 mips_lw (code, mips_ra, mips_sp, cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET);
5454 /* Restore the stack pointer */
5455 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size));
5456 mips_addiu (code, mips_sp, mips_sp, cfg->stack_usage - alloc2_size);
5458 /* Caller will emit either return or tail-call sequence */
5460 cfg->code_len = code - cfg->native_code;
5462 g_assert (cfg->code_len < cfg->code_size);
5463 return (code);
5466 void
5467 mono_arch_emit_epilog (MonoCompile *cfg)
5469 guint8 *code;
5471 code = mono_arch_emit_epilog_sub (cfg, NULL);
5473 mips_jr (code, mips_ra);
5474 mips_nop (code);
5476 cfg->code_len = code - cfg->native_code;
5478 g_assert (cfg->code_len < cfg->code_size);
5481 /* remove once throw_exception_by_name is eliminated */
5482 #if 0
5483 static int
5484 exception_id_by_name (const char *name)
5486 if (strcmp (name, "IndexOutOfRangeException") == 0)
5487 return MONO_EXC_INDEX_OUT_OF_RANGE;
5488 if (strcmp (name, "OverflowException") == 0)
5489 return MONO_EXC_OVERFLOW;
5490 if (strcmp (name, "ArithmeticException") == 0)
5491 return MONO_EXC_ARITHMETIC;
5492 if (strcmp (name, "DivideByZeroException") == 0)
5493 return MONO_EXC_DIVIDE_BY_ZERO;
5494 if (strcmp (name, "InvalidCastException") == 0)
5495 return MONO_EXC_INVALID_CAST;
5496 if (strcmp (name, "NullReferenceException") == 0)
5497 return MONO_EXC_NULL_REF;
5498 if (strcmp (name, "ArrayTypeMismatchException") == 0)
5499 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5500 if (strcmp (name, "ArgumentException") == 0)
5501 return MONO_EXC_ARGUMENT;
5502 g_error ("Unknown intrinsic exception %s\n", name);
5503 return 0;
5505 #endif
5507 void
5508 mono_arch_emit_exceptions (MonoCompile *cfg)
5510 #if 0
5511 MonoJumpInfo *patch_info;
5512 int i;
5513 guint8 *code;
5514 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
5515 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
5516 int max_epilog_size = 50;
5518 /* count the number of exception infos */
5521 * make sure we have enough space for exceptions
5522 * 24 is the simulated call to throw_exception_by_name
5524 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5525 #if 0
5526 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5527 i = exception_id_by_name (patch_info->data.target);
5528 g_assert (i < MONO_EXC_INTRINS_NUM);
5529 if (!exc_throw_found [i]) {
5530 max_epilog_size += 12;
5531 exc_throw_found [i] = TRUE;
5534 #endif
5537 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5538 cfg->code_size *= 2;
5539 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5540 cfg->stat_code_reallocs++;
5543 code = cfg->native_code + cfg->code_len;
5545 /* add code to raise exceptions */
5546 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5547 switch (patch_info->type) {
5548 case MONO_PATCH_INFO_EXC: {
5549 #if 0
5550 //unsigned char *ip = patch_info->ip.i + cfg->native_code;
5552 i = exception_id_by_name (patch_info->data.target);
5553 g_assert (i >= 0 && i < MONO_EXC_INTRINS_NUM);
5554 if (!exc_throw_pos [i]) {
5555 guint32 addr;
5557 exc_throw_pos [i] = code;
5558 //g_print ("exc: writing stub at %p\n", code);
5559 mips_load_const (code, mips_a0, patch_info->data.target);
5560 addr = (guint32) mono_arch_get_throw_exception_by_name ();
5561 mips_load_const (code, mips_t9, addr);
5562 mips_jr (code, mips_t9);
5563 mips_nop (code);
5565 //g_print ("exc: patch %p to %p\n", ip, exc_throw_pos[i]);
5567 /* Turn into a Relative patch, pointing at code stub */
5568 patch_info->type = MONO_PATCH_INFO_METHOD_REL;
5569 patch_info->data.offset = exc_throw_pos[i] - cfg->native_code;
5570 #else
5571 g_assert_not_reached();
5572 #endif
5573 break;
5575 default:
5576 /* do nothing */
5577 break;
5581 cfg->code_len = code - cfg->native_code;
5583 g_assert (cfg->code_len < cfg->code_size);
5584 #endif
5588 * Thread local storage support
5590 static void
5591 setup_tls_access (void)
5593 guint32 ptk;
5594 //guint32 *ins, *code;
5596 if (tls_mode == TLS_MODE_FAILED)
5597 return;
5599 if (g_getenv ("MONO_NO_TLS")) {
5600 tls_mode = TLS_MODE_FAILED;
5601 return;
5604 if (tls_mode == TLS_MODE_DETECT) {
5605 /* XXX */
5606 tls_mode = TLS_MODE_FAILED;
5607 return;
5608 #if 0
5610 ins = (guint32*)pthread_getspecific;
5611 /* uncond branch to the real method */
5612 if ((*ins >> 26) == 18) {
5613 gint32 val;
5614 val = (*ins & ~3) << 6;
5615 val >>= 6;
5616 if (*ins & 2) {
5617 /* absolute */
5618 ins = (guint32*)val;
5619 } else {
5620 ins = (guint32*) ((char*)ins + val);
5623 code = &cmplwi_1023;
5624 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
5625 code = &li_0x48;
5626 ppc_li (code, ppc_r4, 0x48);
5627 code = &blr_ins;
5628 ppc_blr (code);
5629 if (*ins == cmplwi_1023) {
5630 int found_lwz_284 = 0;
5631 for (ptk = 0; ptk < 20; ++ptk) {
5632 ++ins;
5633 if (!*ins || *ins == blr_ins)
5634 break;
5635 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
5636 found_lwz_284 = 1;
5637 break;
5640 if (!found_lwz_284) {
5641 tls_mode = TLS_MODE_FAILED;
5642 return;
5644 tls_mode = TLS_MODE_LTHREADS;
5645 } else if (*ins == li_0x48) {
5646 ++ins;
5647 /* uncond branch to the real method */
5648 if ((*ins >> 26) == 18) {
5649 gint32 val;
5650 val = (*ins & ~3) << 6;
5651 val >>= 6;
5652 if (*ins & 2) {
5653 /* absolute */
5654 ins = (guint32*)val;
5655 } else {
5656 ins = (guint32*) ((char*)ins + val);
5658 code = &val;
5659 ppc_li (code, ppc_r0, 0x7FF2);
5660 if (ins [1] == val) {
5661 /* Darwin on G4, implement */
5662 tls_mode = TLS_MODE_FAILED;
5663 return;
5664 } else {
5665 code = &val;
5666 ppc_mfspr (code, ppc_r3, 104);
5667 if (ins [1] != val) {
5668 tls_mode = TLS_MODE_FAILED;
5669 return;
5671 tls_mode = TLS_MODE_DARWIN_G5;
5673 } else {
5674 tls_mode = TLS_MODE_FAILED;
5675 return;
5677 } else {
5678 tls_mode = TLS_MODE_FAILED;
5679 return;
5681 #endif
5683 if (lmf_pthread_key == -1) {
5684 ptk = mono_jit_tls_id;
5685 if (ptk < 1024) {
5686 /*g_print ("MonoLMF at: %d\n", ptk);*/
5687 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
5688 init_tls_failed = 1;
5689 return;
5691 lmf_pthread_key = ptk;
5694 if (monothread_key == -1) {
5695 ptk = mono_thread_get_tls_key ();
5696 if (ptk < 1024) {
5697 monothread_key = ptk;
5698 /*g_print ("thread inited: %d\n", ptk);*/
5699 } else {
5700 /*g_print ("thread not inited yet %d\n", ptk);*/
5705 void
5706 mono_arch_finish_init (void)
5708 setup_tls_access ();
5711 void
5712 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5716 void
5717 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
5719 int this_dreg = mips_a0;
5721 if (vt_reg != -1)
5722 this_dreg = mips_a1;
5724 /* add the this argument */
5725 if (this_reg != -1) {
5726 MonoInst *this_ins;
5727 MONO_INST_NEW (cfg, this_ins, OP_MOVE);
5728 this_ins->type = this_type;
5729 this_ins->sreg1 = this_reg;
5730 this_ins->dreg = mono_alloc_ireg (cfg);
5731 mono_bblock_add_inst (cfg->cbb, this_ins);
5732 mono_call_inst_add_outarg_reg (cfg, inst, this_ins->dreg, this_dreg, FALSE);
5735 if (vt_reg != -1) {
5736 MonoInst *vtarg;
5737 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
5738 vtarg->type = STACK_MP;
5739 vtarg->sreg1 = vt_reg;
5740 vtarg->dreg = mono_alloc_ireg (cfg);
5741 mono_bblock_add_inst (cfg->cbb, vtarg);
5742 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, mips_a0, FALSE);
5746 MonoInst*
5747 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5749 MonoInst *ins = NULL;
5751 return ins;
5754 MonoInst*
5755 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5757 return NULL;
5760 gboolean
5761 mono_arch_print_tree (MonoInst *tree, int arity)
5763 return 0;
5766 mgreg_t
5767 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5769 return ctx->sc_regs [reg];
5772 #define ENABLE_WRONG_METHOD_CHECK 0
5774 #define MIPS_LOAD_SEQUENCE_LENGTH 8
5775 #define CMP_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 4)
5776 #define BR_SIZE 8
5777 #define LOADSTORE_SIZE 4
5778 #define JUMP_IMM_SIZE 16
5779 #define JUMP_IMM32_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 8)
5780 #define LOAD_CONST_SIZE 8
5781 #define JUMP_JR_SIZE 8
5784 * LOCKING: called with the domain lock held
5786 gpointer
5787 mono_arch_build_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5788 gpointer fail_tramp)
5790 int i;
5791 int size = 0;
5792 guint8 *code, *start, *patch;
5794 for (i = 0; i < count; ++i) {
5795 MonoIMTCheckItem *item = imt_entries [i];
5797 if (item->is_equals) {
5798 if (item->check_target_idx) {
5799 item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_JR_SIZE;
5800 if (item->has_target_code)
5801 item->chunk_size += LOAD_CONST_SIZE;
5802 else
5803 item->chunk_size += LOADSTORE_SIZE;
5804 } else {
5805 if (fail_tramp) {
5806 item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_IMM32_SIZE +
5807 LOADSTORE_SIZE + JUMP_IMM32_SIZE;
5808 if (!item->has_target_code)
5809 item->chunk_size += LOADSTORE_SIZE;
5810 } else {
5811 item->chunk_size += LOADSTORE_SIZE + JUMP_JR_SIZE;
5812 #if ENABLE_WRONG_METHOD_CHECK
5813 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5814 #endif
5817 } else {
5818 item->chunk_size += CMP_SIZE + BR_SIZE;
5819 imt_entries [item->check_target_idx]->compare_done = TRUE;
5821 size += item->chunk_size;
5823 /* the initial load of the vtable address */
5824 size += MIPS_LOAD_SEQUENCE_LENGTH;
5825 if (fail_tramp) {
5826 code = mono_method_alloc_generic_virtual_trampoline (domain, size);
5827 } else {
5828 code = mono_domain_code_reserve (domain, size);
5830 start = code;
5832 /* t7 points to the vtable */
5833 mips_load_const (code, mips_t7, (gsize)(& (vtable->vtable [0])));
5835 for (i = 0; i < count; ++i) {
5836 MonoIMTCheckItem *item = imt_entries [i];
5838 item->code_target = code;
5839 if (item->is_equals) {
5840 if (item->check_target_idx) {
5841 mips_load_const (code, mips_temp, (gsize)item->key);
5842 item->jmp_code = code;
5843 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5844 mips_nop (code);
5845 if (item->has_target_code) {
5846 mips_load_const (code, mips_t9,
5847 item->value.target_code);
5849 else {
5850 mips_lw (code, mips_t9, mips_t7,
5851 (sizeof (gpointer) * item->value.vtable_slot));
5853 mips_jr (code, mips_t9);
5854 mips_nop (code);
5855 } else {
5856 if (fail_tramp) {
5857 mips_load_const (code, mips_temp, (gsize)item->key);
5858 patch = code;
5859 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5860 mips_nop (code);
5861 if (item->has_target_code) {
5862 mips_load_const (code, mips_t9,
5863 item->value.target_code);
5864 } else {
5865 g_assert (vtable);
5866 mips_load_const (code, mips_at,
5867 & (vtable->vtable [item->value.vtable_slot]));
5868 mips_lw (code, mips_t9, mips_at, 0);
5870 mips_jr (code, mips_t9);
5871 mips_nop (code);
5872 mips_patch ((guint32 *)(void *)patch, (guint32)code);
5873 mips_load_const (code, mips_t9, fail_tramp);
5874 mips_jr (code, mips_t9);
5875 mips_nop (code);
5876 } else {
5877 /* enable the commented code to assert on wrong method */
5878 #if ENABLE_WRONG_METHOD_CHECK
5879 ppc_load (code, ppc_r0, (guint32)item->key);
5880 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5881 patch = code;
5882 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5883 #endif
5884 mips_lw (code, mips_t9, mips_t7,
5885 (sizeof (gpointer) * item->value.vtable_slot));
5886 mips_jr (code, mips_t9);
5887 mips_nop (code);
5889 #if ENABLE_WRONG_METHOD_CHECK
5890 ppc_patch (patch, code);
5891 ppc_break (code);
5892 #endif
5895 } else {
5896 mips_load_const (code, mips_temp, (gulong)item->key);
5897 mips_slt (code, mips_temp, MONO_ARCH_IMT_REG, mips_temp);
5899 item->jmp_code = code;
5900 mips_beq (code, mips_temp, mips_zero, 0);
5901 mips_nop (code);
5904 /* patch the branches to get to the target items */
5905 for (i = 0; i < count; ++i) {
5906 MonoIMTCheckItem *item = imt_entries [i];
5907 if (item->jmp_code && item->check_target_idx) {
5908 mips_patch ((guint32 *)item->jmp_code,
5909 (guint32)imt_entries [item->check_target_idx]->code_target);
5913 if (!fail_tramp)
5914 mono_stats.imt_trampolines_size += code - start;
5915 g_assert (code - start <= size);
5916 mono_arch_flush_icache (start, size);
5918 mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), domain);
5920 return start;
5923 MonoMethod*
5924 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
5926 return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
5929 MonoVTable*
5930 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
5932 return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
5935 /* Soft Debug support */
5936 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
5939 * mono_arch_set_breakpoint:
5941 * See mini-amd64.c for docs.
5943 void
5944 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
5946 guint8 *code = ip;
5947 guint32 addr = (guint32)bp_trigger_page;
5949 mips_load_const (code, mips_t9, addr);
5950 mips_lw (code, mips_t9, mips_t9, 0);
5952 mono_arch_flush_icache (ip, code - ip);
5956 * mono_arch_clear_breakpoint:
5958 * See mini-amd64.c for docs.
5960 void
5961 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
5963 guint8 *code = ip;
5965 mips_nop (code);
5966 mips_nop (code);
5967 mips_nop (code);
5969 mono_arch_flush_icache (ip, code - ip);
5973 * mono_arch_start_single_stepping:
5975 * See mini-amd64.c for docs.
5977 void
5978 mono_arch_start_single_stepping (void)
5980 mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
5984 * mono_arch_stop_single_stepping:
5986 * See mini-amd64.c for docs.
5988 void
5989 mono_arch_stop_single_stepping (void)
5991 mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
5995 * mono_arch_is_single_step_event:
5997 * See mini-amd64.c for docs.
5999 gboolean
6000 mono_arch_is_single_step_event (void *info, void *sigctx)
6002 siginfo_t* sinfo = (siginfo_t*) info;
6003 /* Sometimes the address is off by 4 */
6004 if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
6005 return TRUE;
6006 else
6007 return FALSE;
6011 * mono_arch_is_breakpoint_event:
6013 * See mini-amd64.c for docs.
6015 gboolean
6016 mono_arch_is_breakpoint_event (void *info, void *sigctx)
6018 siginfo_t* sinfo = (siginfo_t*) info;
6019 /* Sometimes the address is off by 4 */
6020 if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
6021 return TRUE;
6022 else
6023 return FALSE;
6027 * mono_arch_skip_breakpoint:
6029 * See mini-amd64.c for docs.
6031 void
6032 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
6034 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
6038 * mono_arch_skip_single_step:
6040 * See mini-amd64.c for docs.
6042 void
6043 mono_arch_skip_single_step (MonoContext *ctx)
6045 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
6049 * mono_arch_get_seq_point_info:
6051 * See mini-amd64.c for docs.
6053 gpointer
6054 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
6056 NOT_IMPLEMENTED;
6057 return NULL;
6060 void
6061 mono_arch_init_lmf_ext (MonoLMFExt *ext, gpointer prev_lmf)
6063 ext->lmf.previous_lmf = prev_lmf;
6064 /* Mark that this is a MonoLMFExt */
6065 ext->lmf.previous_lmf = (gpointer)(((gssize)ext->lmf.previous_lmf) | 2);
6066 ext->lmf.iregs [mips_sp] = (gssize)ext;
6069 #endif /* MONO_ARCH_SOFT_DEBUG_SUPPORTED */
6071 gboolean
6072 mono_arch_opcode_supported (int opcode)
6074 return FALSE;