update rx (mobile builds).
[mono-project.git] / mono / mini / mini-mips.c
blob12d17c399a1fd074d5aa99079e52cc79c50c349f
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/appdomain.h>
19 #include <mono/metadata/debug-helpers.h>
20 #include <mono/utils/mono-mmap.h>
22 #include <mono/arch/mips/mips-codegen.h>
24 #include "mini-mips.h"
25 #include "cpu-mips.h"
26 #include "trace.h"
27 #include "ir-emit.h"
29 #define SAVE_FP_REGS 0
31 #define ALWAYS_SAVE_RA 1 /* call-handler & switch currently clobber ra */
33 #define PROMOTE_R4_TO_R8 1 /* promote single values in registers to doubles */
34 #define USE_MUL 1 /* use mul instead of mult/mflo for multiply */
36 /* Emit a call sequence to 'v', using 'D' as a scratch register if necessary */
37 #define mips_call(c,D,v) do { \
38 guint32 _target = (guint32)(v); \
39 if (1 || ((v) == NULL) || ((_target & 0xfc000000) != (((guint32)(c)) & 0xfc000000))) { \
40 mips_load_const (c, D, _target); \
41 mips_jalr (c, D, mips_ra); \
42 } \
43 else { \
44 mips_jumpl (c, _target >> 2); \
45 } \
46 mips_nop (c); \
47 } while (0)
49 enum {
50 TLS_MODE_DETECT,
51 TLS_MODE_FAILED,
52 TLS_MODE_LTHREADS,
53 TLS_MODE_NPTL
56 /* This mutex protects architecture specific caches */
57 #define mono_mini_arch_lock() EnterCriticalSection (&mini_arch_mutex)
58 #define mono_mini_arch_unlock() LeaveCriticalSection (&mini_arch_mutex)
59 static CRITICAL_SECTION mini_arch_mutex;
61 int mono_exc_esp_offset = 0;
62 static int tls_mode = TLS_MODE_DETECT;
63 static int lmf_pthread_key = -1;
64 static int monothread_key = -1;
65 static int monodomain_key = -1;
67 /* Whenever the host is little-endian */
68 static int little_endian;
69 /* Index of ms word/register */
70 static int ls_word_idx;
71 /* Index of ls word/register */
72 static int ms_word_idx;
73 /* Same for offsets */
74 static int ls_word_offset;
75 static int ms_word_offset;
78 * The code generated for sequence points reads from this location, which is
79 * made read-only when single stepping is enabled.
81 static gpointer ss_trigger_page;
83 /* Enabled breakpoints read from this trigger page */
84 static gpointer bp_trigger_page;
86 #undef DEBUG
87 #define DEBUG(a) if (cfg->verbose_level > 1) a
88 #undef DEBUG
89 #define DEBUG(a) a
90 #undef DEBUG
91 #define DEBUG(a)
93 #define EMIT_SYSTEM_EXCEPTION_NAME(exc_name) \
94 do { \
95 code = mips_emit_exc_by_name (code, exc_name); \
96 cfg->bb_exit->max_offset += 16; \
97 } while (0)
100 #define emit_linuxthreads_tls(code,dreg,key) do {\
101 int off1, off2; \
102 off1 = offsets_from_pthread_key ((key), &off2); \
103 g_assert_not_reached (); \
104 ppc_lwz ((code), (dreg), off1, ppc_r2); \
105 ppc_lwz ((code), (dreg), off2, (dreg)); \
106 } while (0);
109 #define emit_tls_access(code,dreg,key) do { \
110 switch (tls_mode) { \
111 case TLS_MODE_LTHREADS: emit_linuxthreads_tls(code,dreg,key); break; \
112 default: g_assert_not_reached (); \
114 } while (0)
116 #define MONO_EMIT_NEW_LOAD_R8(cfg,dr,addr) do { \
117 MonoInst *inst; \
118 MONO_INST_NEW ((cfg), (inst), OP_R8CONST); \
119 inst->type = STACK_R8; \
120 inst->dreg = (dr); \
121 inst->inst_p0 = (void*)(addr); \
122 mono_bblock_add_inst (cfg->cbb, inst); \
123 } while (0)
125 #define ins_is_compare(ins) ((ins) && (((ins)->opcode == OP_COMPARE) \
126 || ((ins)->opcode == OP_ICOMPARE) \
127 || ((ins)->opcode == OP_LCOMPARE)))
128 #define ins_is_compare_imm(ins) ((ins) && (((ins)->opcode == OP_COMPARE_IMM) \
129 || ((ins)->opcode == OP_ICOMPARE_IMM) \
130 || ((ins)->opcode == OP_LCOMPARE_IMM)))
132 #define INS_REWRITE(ins, op, _s1, _s2) do { \
133 int s1 = _s1; \
134 int s2 = _s2; \
135 ins->opcode = (op); \
136 ins->sreg1 = (s1); \
137 ins->sreg2 = (s2); \
138 } while (0);
140 #define INS_REWRITE_IMM(ins, op, _s1, _imm) do { \
141 int s1 = _s1; \
142 ins->opcode = (op); \
143 ins->sreg1 = (s1); \
144 ins->inst_imm = (_imm); \
145 } while (0);
148 typedef struct InstList InstList;
150 struct InstList {
151 InstList *prev;
152 InstList *next;
153 MonoInst *data;
156 typedef enum {
157 ArgInIReg,
158 ArgOnStack,
159 ArgInFReg,
160 ArgStructByVal,
161 ArgStructByAddr
162 } ArgStorage;
164 typedef struct {
165 gint32 offset;
166 guint16 vtsize; /* in param area */
167 guint8 reg;
168 ArgStorage storage;
169 guint8 size : 4; /* 1, 2, 4, 8, or regs used by ArgStructByVal */
170 } ArgInfo;
172 typedef struct {
173 int nargs;
174 int gr;
175 int fr;
176 gboolean gr_passed;
177 gboolean on_stack;
178 gboolean vtype_retaddr;
179 int stack_size;
180 guint32 stack_usage;
181 guint32 struct_ret;
182 ArgInfo ret;
183 ArgInfo sig_cookie;
184 ArgInfo args [1];
185 } CallInfo;
187 void patch_lui_addiu(guint32 *ip, guint32 val);
188 guint8 *mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code);
189 guint8 *mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins);
190 void mips_adjust_stackframe(MonoCompile *cfg);
191 void mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg);
192 MonoInst *mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args);
195 /* Not defined in asm/cachectl.h */
196 int cacheflush(char *addr, int nbytes, int cache);
198 void
199 mono_arch_flush_icache (guint8 *code, gint size)
201 /* Linux/MIPS specific */
202 cacheflush ((char*)code, size, BCACHE);
205 void
206 mono_arch_flush_register_windows (void)
210 gboolean
211 mono_arch_is_inst_imm (gint64 imm)
213 return TRUE;
216 static guint8 *
217 mips_emit_exc_by_name(guint8 *code, const char *name)
219 gpointer addr;
220 MonoClass *exc_class;
222 exc_class = mono_class_from_name (mono_defaults.corlib, "System", name);
223 g_assert (exc_class);
225 mips_load_const (code, mips_a0, exc_class->type_token);
226 addr = mono_get_throw_corlib_exception ();
227 mips_call (code, mips_t9, addr);
228 return code;
232 guint8 *
233 mips_emit_load_const(guint8 *code, int dreg, mgreg_t v)
235 if (mips_is_imm16 (v))
236 mips_addiu (code, dreg, mips_zero, ((guint32)v) & 0xffff);
237 else {
238 #if SIZEOF_REGISTER == 8
239 if (v != (long) v) {
240 /* v is not a sign-extended 32-bit value */
241 mips_lui (code, dreg, mips_zero, (guint32)((v >> (32+16)) & 0xffff));
242 mips_ori (code, dreg, dreg, (guint32)((v >> (32)) & 0xffff));
243 mips_dsll (code, dreg, dreg, 16);
244 mips_ori (code, dreg, dreg, (guint32)((v >> (16)) & 0xffff));
245 mips_dsll (code, dreg, dreg, 16);
246 mips_ori (code, dreg, dreg, (guint32)(v & 0xffff));
247 return code;
249 #endif
250 if (((guint32)v) & (1 << 15)) {
251 mips_lui (code, dreg, mips_zero, (((guint32)v)>>16)+1);
253 else {
254 mips_lui (code, dreg, mips_zero, (((guint32)v)>>16));
256 if (((guint32)v) & 0xffff)
257 mips_addiu (code, dreg, dreg, ((guint32)v) & 0xffff);
259 return code;
262 guint8 *
263 mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins)
265 g_assert (ins);
266 if (cfg->arch.long_branch) {
267 int br_offset = 5;
269 /* Invert test and emit branch around jump */
270 switch (op) {
271 case OP_MIPS_BEQ:
272 mips_bne (code, ins->sreg1, ins->sreg2, br_offset);
273 mips_nop (code);
274 break;
275 case OP_MIPS_BNE:
276 mips_beq (code, ins->sreg1, ins->sreg2, br_offset);
277 mips_nop (code);
278 break;
279 case OP_MIPS_BGEZ:
280 mips_bltz (code, ins->sreg1, br_offset);
281 mips_nop (code);
282 break;
283 case OP_MIPS_BGTZ:
284 mips_blez (code, ins->sreg1, br_offset);
285 mips_nop (code);
286 break;
287 case OP_MIPS_BLEZ:
288 mips_bgtz (code, ins->sreg1, br_offset);
289 mips_nop (code);
290 break;
291 case OP_MIPS_BLTZ:
292 mips_bgez (code, ins->sreg1, br_offset);
293 mips_nop (code);
294 break;
295 default:
296 g_assert_not_reached ();
298 mono_add_patch_info (cfg, code - cfg->native_code,
299 MONO_PATCH_INFO_BB, ins->inst_true_bb);
300 mips_lui (code, mips_at, mips_zero, 0);
301 mips_addiu (code, mips_at, mips_at, 0);
302 mips_jr (code, mips_at);
303 mips_nop (code);
305 else {
306 mono_add_patch_info (cfg, code - cfg->native_code,
307 MONO_PATCH_INFO_BB, ins->inst_true_bb);
308 switch (op) {
309 case OP_MIPS_BEQ:
310 mips_beq (code, ins->sreg1, ins->sreg2, 0);
311 mips_nop (code);
312 break;
313 case OP_MIPS_BNE:
314 mips_bne (code, ins->sreg1, ins->sreg2, 0);
315 mips_nop (code);
316 break;
317 case OP_MIPS_BGEZ:
318 mips_bgez (code, ins->sreg1, 0);
319 mips_nop (code);
320 break;
321 case OP_MIPS_BGTZ:
322 mips_bgtz (code, ins->sreg1, 0);
323 mips_nop (code);
324 break;
325 case OP_MIPS_BLEZ:
326 mips_blez (code, ins->sreg1, 0);
327 mips_nop (code);
328 break;
329 case OP_MIPS_BLTZ:
330 mips_bltz (code, ins->sreg1, 0);
331 mips_nop (code);
332 break;
333 default:
334 g_assert_not_reached ();
337 return (code);
340 /* XXX - big-endian dependent? */
341 void
342 patch_lui_addiu(guint32 *ip, guint32 val)
344 guint16 *__lui_addiu = (guint16*)(void *)(ip);
346 #if 0
347 printf ("patch_lui_addiu ip=0x%08x (0x%08x, 0x%08x) to point to 0x%08x\n",
348 ip, ((guint32 *)ip)[0], ((guint32 *)ip)[1], val);
349 fflush (stdout);
350 #endif
351 if (((guint32)(val)) & (1 << 15))
352 __lui_addiu [MINI_LS_WORD_IDX] = ((((guint32)(val)) >> 16) & 0xffff) + 1;
353 else
354 __lui_addiu [MINI_LS_WORD_IDX] = (((guint32)(val)) >> 16) & 0xffff;
355 __lui_addiu [MINI_LS_WORD_IDX + 2] = ((guint32)(val)) & 0xffff;
356 mono_arch_flush_icache ((guint8 *)ip, 8);
359 guint32 trap_target;
360 void
361 mips_patch (guint32 *code, guint32 target)
363 guint32 ins = *code;
364 guint32 op = ins >> 26;
365 guint32 diff, offset;
367 g_assert (trap_target != target);
368 //printf ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
369 switch (op) {
370 case 0x00: /* jr ra */
371 if (ins == 0x3e00008)
372 break;
373 g_assert_not_reached ();
374 break;
375 case 0x02: /* j */
376 case 0x03: /* jal */
377 g_assert (!(target & 0x03));
378 g_assert ((target & 0xfc000000) == (((guint32)code) & 0xfc000000));
379 ins = (ins & 0xfc000000) | (((target) >> 2) & 0x03ffffff);
380 *code = ins;
381 mono_arch_flush_icache ((guint8 *)code, 4);
382 break;
383 case 0x01: /* BLTZ */
384 case 0x04: /* BEQ */
385 case 0x05: /* BNE */
386 case 0x06: /* BLEZ */
387 case 0x07: /* BGTZ */
388 case 0x11: /* bc1t */
389 diff = target - (guint32)(code + 1);
390 g_assert (((diff & 0x0003ffff) == diff) || ((diff | 0xfffc0000) == diff));
391 g_assert (!(diff & 0x03));
392 offset = ((gint32)diff) >> 2;
393 if (((int)offset) != ((int)(short)offset))
394 g_assert (((int)offset) == ((int)(short)offset));
395 ins = (ins & 0xffff0000) | (offset & 0x0000ffff);
396 *code = ins;
397 mono_arch_flush_icache ((guint8 *)code, 4);
398 break;
399 case 0x0f: /* LUI / ADDIU pair */
400 g_assert ((code[1] >> 26) == 0x9);
401 patch_lui_addiu (code, target);
402 mono_arch_flush_icache ((guint8 *)code, 8);
403 break;
405 default:
406 printf ("unknown op 0x%02x (0x%08x) @ %p\n", op, ins, code);
407 g_assert_not_reached ();
411 #if 0
412 static int
413 offsets_from_pthread_key (guint32 key, int *offset2)
415 int idx1 = key / 32;
416 int idx2 = key % 32;
417 *offset2 = idx2 * sizeof (gpointer);
418 return 284 + idx1 * sizeof (gpointer);
420 #endif
422 static void mono_arch_compute_omit_fp (MonoCompile *cfg);
424 const char*
425 mono_arch_regname (int reg) {
426 #if _MIPS_SIM == _ABIO32
427 static const char * rnames[] = {
428 "zero", "at", "v0", "v1",
429 "a0", "a1", "a2", "a3",
430 "t0", "t1", "t2", "t3",
431 "t4", "t5", "t6", "t7",
432 "s0", "s1", "s2", "s3",
433 "s4", "s5", "s6", "s7",
434 "t8", "t9", "k0", "k1",
435 "gp", "sp", "fp", "ra"
437 #elif _MIPS_SIM == _ABIN32
438 static const char * rnames[] = {
439 "zero", "at", "v0", "v1",
440 "a0", "a1", "a2", "a3",
441 "a4", "a5", "a6", "a7",
442 "t0", "t1", "t2", "t3",
443 "s0", "s1", "s2", "s3",
444 "s4", "s5", "s6", "s7",
445 "t8", "t9", "k0", "k1",
446 "gp", "sp", "fp", "ra"
448 #endif
449 if (reg >= 0 && reg < 32)
450 return rnames [reg];
451 return "unknown";
454 const char*
455 mono_arch_fregname (int reg) {
456 static const char * rnames[] = {
457 "f0", "f1", "f2", "f3",
458 "f4", "f5", "f6", "f7",
459 "f8", "f9", "f10", "f11",
460 "f12", "f13", "f14", "f15",
461 "f16", "f17", "f18", "f19",
462 "f20", "f21", "f22", "f23",
463 "f24", "f25", "f26", "f27",
464 "f28", "f29", "f30", "f31"
466 if (reg >= 0 && reg < 32)
467 return rnames [reg];
468 return "unknown";
471 /* this function overwrites at */
472 static guint8*
473 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
475 /* XXX write a loop, not an unrolled loop */
476 while (size > 0) {
477 mips_lw (code, mips_at, sreg, soffset);
478 mips_sw (code, mips_at, dreg, doffset);
479 size -= 4;
480 soffset += 4;
481 doffset += 4;
483 return code;
487 * mono_arch_get_argument_info:
488 * @csig: a method signature
489 * @param_count: the number of parameters to consider
490 * @arg_info: an array to store the result infos
492 * Gathers information on parameters such as size, alignment and
493 * padding. arg_info should be large enought to hold param_count + 1 entries.
495 * Returns the size of the activation frame.
498 mono_arch_get_argument_info (MonoGenericSharingContext *gsctx, MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
500 int k, frame_size = 0;
501 guint32 size, align, pad;
502 int offset = 0;
504 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
505 frame_size += sizeof (gpointer);
506 offset += 4;
509 arg_info [0].offset = offset;
511 if (csig->hasthis) {
512 frame_size += sizeof (gpointer);
513 offset += 4;
516 arg_info [0].size = frame_size;
518 for (k = 0; k < param_count; k++) {
519 size = mini_type_stack_size_full (NULL, csig->params [k], &align, csig->pinvoke);
521 /* ignore alignment for now */
522 align = 1;
524 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
525 arg_info [k].pad = pad;
526 frame_size += size;
527 arg_info [k + 1].pad = 0;
528 arg_info [k + 1].size = size;
529 offset += pad;
530 arg_info [k + 1].offset = offset;
531 offset += size;
534 align = MONO_ARCH_FRAME_ALIGNMENT;
535 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
536 arg_info [k].pad = pad;
538 return frame_size;
541 /* The delegate object plus 3 params */
542 #define MAX_ARCH_DELEGATE_PARAMS (4 - 1)
544 static gpointer
545 get_delegate_invoke_impl (gboolean has_target, gboolean param_count, guint32 *code_size)
547 guint8 *code, *start;
549 if (has_target) {
550 start = code = mono_global_codeman_reserve (16);
552 /* Replace the this argument with the target */
553 mips_lw (code, mips_temp, mips_a0, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
554 mips_lw (code, mips_a0, mips_a0, G_STRUCT_OFFSET (MonoDelegate, target));
555 mips_jr (code, mips_temp);
556 mips_nop (code);
558 g_assert ((code - start) <= 16);
560 mono_arch_flush_icache (start, 16);
561 } else {
562 int size, i;
564 size = 16 + param_count * 4;
565 start = code = mono_global_codeman_reserve (size);
567 mips_lw (code, mips_temp, mips_a0, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
568 /* slide down the arguments */
569 for (i = 0; i < param_count; ++i) {
570 mips_move (code, mips_a0 + i, mips_a0 + i + 1);
572 mips_jr (code, mips_temp);
573 mips_nop (code);
575 g_assert ((code - start) <= size);
577 mono_arch_flush_icache (start, size);
580 if (code_size)
581 *code_size = code - start;
583 return start;
587 * mono_arch_get_delegate_invoke_impls:
589 * Return a list of MonoAotTrampInfo structures for the delegate invoke impl
590 * trampolines.
592 GSList*
593 mono_arch_get_delegate_invoke_impls (void)
595 GSList *res = NULL;
596 guint8 *code;
597 guint32 code_len;
598 int i;
600 code = get_delegate_invoke_impl (TRUE, 0, &code_len);
601 res = g_slist_prepend (res, mono_tramp_info_create (g_strdup ("delegate_invoke_impl_has_target"), code, code_len, NULL, NULL));
603 for (i = 0; i <= MAX_ARCH_DELEGATE_PARAMS; ++i) {
604 code = get_delegate_invoke_impl (FALSE, i, &code_len);
605 res = g_slist_prepend (res, mono_tramp_info_create (g_strdup_printf ("delegate_invoke_impl_target_%d", i), code, code_len, NULL, NULL));
608 return res;
611 gpointer
612 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
614 guint8 *code, *start;
616 /* FIXME: Support more cases */
617 if (MONO_TYPE_ISSTRUCT (sig->ret))
618 return NULL;
620 if (has_target) {
621 static guint8* cached = NULL;
622 mono_mini_arch_lock ();
623 if (cached) {
624 mono_mini_arch_unlock ();
625 return cached;
628 if (mono_aot_only)
629 start = mono_aot_get_trampoline ("delegate_invoke_impl_has_target");
630 else
631 start = get_delegate_invoke_impl (TRUE, 0, NULL);
632 cached = start;
633 mono_mini_arch_unlock ();
634 return cached;
635 } else {
636 static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
637 int i;
639 if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
640 return NULL;
641 for (i = 0; i < sig->param_count; ++i)
642 if (!mono_is_regsize_var (sig->params [i]))
643 return NULL;
645 mono_mini_arch_lock ();
646 code = cache [sig->param_count];
647 if (code) {
648 mono_mini_arch_unlock ();
649 return code;
652 if (mono_aot_only) {
653 char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", sig->param_count);
654 start = mono_aot_get_trampoline (name);
655 g_free (name);
656 } else {
657 start = get_delegate_invoke_impl (FALSE, sig->param_count, NULL);
659 cache [sig->param_count] = start;
660 mono_mini_arch_unlock ();
661 return start;
664 return NULL;
667 gpointer
668 mono_arch_get_this_arg_from_call (mgreg_t *regs, guint8 *code)
670 g_assert(regs);
671 return (gpointer)regs [mips_a0];
675 * Initialize the cpu to execute managed code.
677 void
678 mono_arch_cpu_init (void)
680 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
681 little_endian = 1;
682 ls_word_idx = 0;
683 ms_word_idx = 1;
684 #else
685 ls_word_idx = 1;
686 ms_word_idx = 0;
687 #endif
689 ls_word_offset = ls_word_idx * 4;
690 ms_word_offset = ms_word_idx * 4;
694 * Initialize architecture specific code.
696 void
697 mono_arch_init (void)
699 InitializeCriticalSection (&mini_arch_mutex);
701 ss_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
702 bp_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
703 mono_mprotect (bp_trigger_page, mono_pagesize (), 0);
707 * Cleanup architecture specific code.
709 void
710 mono_arch_cleanup (void)
712 DeleteCriticalSection (&mini_arch_mutex);
716 * This function returns the optimizations supported on this cpu.
718 guint32
719 mono_arch_cpu_optimizations (guint32 *exclude_mask)
721 guint32 opts = 0;
723 /* no mips-specific optimizations yet */
724 *exclude_mask = 0;
725 return opts;
729 * This function test for all SIMD functions supported.
731 * Returns a bitmask corresponding to all supported versions.
734 guint32
735 mono_arch_cpu_enumerate_simd_versions (void)
737 /* SIMD is currently unimplemented */
738 return 0;
741 GList *
742 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
744 GList *vars = NULL;
745 int i;
747 for (i = 0; i < cfg->num_varinfo; i++) {
748 MonoInst *ins = cfg->varinfo [i];
749 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
751 /* unused vars */
752 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
753 continue;
755 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
756 continue;
758 /* we can only allocate 32 bit values */
759 if (mono_is_regsize_var (ins->inst_vtype)) {
760 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
761 g_assert (i == vmv->idx);
762 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
766 return vars;
769 GList *
770 mono_arch_get_global_int_regs (MonoCompile *cfg)
772 GList *regs = NULL;
774 regs = g_list_prepend (regs, (gpointer)mips_s0);
775 regs = g_list_prepend (regs, (gpointer)mips_s1);
776 regs = g_list_prepend (regs, (gpointer)mips_s2);
777 regs = g_list_prepend (regs, (gpointer)mips_s3);
778 regs = g_list_prepend (regs, (gpointer)mips_s4);
779 //regs = g_list_prepend (regs, (gpointer)mips_s5);
780 regs = g_list_prepend (regs, (gpointer)mips_s6);
781 regs = g_list_prepend (regs, (gpointer)mips_s7);
783 return regs;
787 * mono_arch_regalloc_cost:
789 * Return the cost, in number of memory references, of the action of
790 * allocating the variable VMV into a register during global register
791 * allocation.
793 guint32
794 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
796 /* FIXME: */
797 return 2;
800 static void
801 args_onto_stack (CallInfo *info)
803 g_assert (!info->on_stack);
804 g_assert (info->stack_size <= MIPS_STACK_PARAM_OFFSET);
805 info->on_stack = TRUE;
806 info->stack_size = MIPS_STACK_PARAM_OFFSET;
809 #if _MIPS_SIM == _ABIO32
811 * O32 calling convention version
814 static void
815 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
816 /* First, see if we need to drop onto the stack */
817 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
818 args_onto_stack (info);
820 /* Now, place the argument */
821 if (info->on_stack) {
822 ainfo->storage = ArgOnStack;
823 ainfo->reg = mips_sp; /* in the caller */
824 ainfo->offset = info->stack_size;
826 else {
827 ainfo->storage = ArgInIReg;
828 ainfo->reg = info->gr;
829 info->gr += 1;
830 info->gr_passed = TRUE;
832 info->stack_size += 4;
835 static void
836 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
837 /* First, see if we need to drop onto the stack */
838 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
839 args_onto_stack (info);
841 /* Now, place the argument */
842 if (info->on_stack) {
843 g_assert (info->stack_size % 4 == 0);
844 info->stack_size += (info->stack_size % 8);
846 ainfo->storage = ArgOnStack;
847 ainfo->reg = mips_sp; /* in the caller */
848 ainfo->offset = info->stack_size;
850 else {
851 // info->gr must be a0 or a2
852 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
853 g_assert(info->gr <= MIPS_LAST_ARG_REG);
855 ainfo->storage = ArgInIReg;
856 ainfo->reg = info->gr;
857 info->gr += 2;
858 info->gr_passed = TRUE;
860 info->stack_size += 8;
863 static void
864 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
865 /* First, see if we need to drop onto the stack */
866 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
867 args_onto_stack (info);
869 /* Now, place the argument */
870 if (info->on_stack) {
871 ainfo->storage = ArgOnStack;
872 ainfo->reg = mips_sp; /* in the caller */
873 ainfo->offset = info->stack_size;
875 else {
876 /* Only use FP regs for args if no int args passed yet */
877 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
878 ainfo->storage = ArgInFReg;
879 ainfo->reg = info->fr;
880 /* Even though it's a single-precision float, it takes up two FP regs */
881 info->fr += 2;
882 /* FP and GP slots do not overlap */
883 info->gr += 1;
885 else {
886 /* Passing single-precision float arg in a GP register
887 * such as: func (0, 1.0, 2, 3);
888 * In this case, only one 'gr' register is consumed.
890 ainfo->storage = ArgInIReg;
891 ainfo->reg = info->gr;
893 info->gr += 1;
894 info->gr_passed = TRUE;
897 info->stack_size += 4;
900 static void
901 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
902 /* First, see if we need to drop onto the stack */
903 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
904 args_onto_stack (info);
906 /* Now, place the argument */
907 if (info->on_stack) {
908 g_assert(info->stack_size % 4 == 0);
909 info->stack_size += (info->stack_size % 8);
911 ainfo->storage = ArgOnStack;
912 ainfo->reg = mips_sp; /* in the caller */
913 ainfo->offset = info->stack_size;
915 else {
916 /* Only use FP regs for args if no int args passed yet */
917 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
918 ainfo->storage = ArgInFReg;
919 ainfo->reg = info->fr;
920 info->fr += 2;
921 /* FP and GP slots do not overlap */
922 info->gr += 2;
924 else {
925 // info->gr must be a0 or a2
926 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
927 g_assert(info->gr <= MIPS_LAST_ARG_REG);
929 ainfo->storage = ArgInIReg;
930 ainfo->reg = info->gr;
931 info->gr += 2;
932 info->gr_passed = TRUE;
935 info->stack_size += 8;
937 #elif _MIPS_SIM == _ABIN32
939 * N32 calling convention version
942 static void
943 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
944 /* First, see if we need to drop onto the stack */
945 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
946 args_onto_stack (info);
948 /* Now, place the argument */
949 if (info->on_stack) {
950 ainfo->storage = ArgOnStack;
951 ainfo->reg = mips_sp; /* in the caller */
952 ainfo->offset = info->stack_size;
953 info->stack_size += SIZEOF_REGISTER;
955 else {
956 ainfo->storage = ArgInIReg;
957 ainfo->reg = info->gr;
958 info->gr += 1;
959 info->gr_passed = TRUE;
963 static void
964 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
965 /* First, see if we need to drop onto the stack */
966 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
967 args_onto_stack (info);
969 /* Now, place the argument */
970 if (info->on_stack) {
971 g_assert (info->stack_size % 4 == 0);
972 info->stack_size += (info->stack_size % 8);
974 ainfo->storage = ArgOnStack;
975 ainfo->reg = mips_sp; /* in the caller */
976 ainfo->offset = info->stack_size;
977 info->stack_size += SIZEOF_REGISTER;
979 else {
980 g_assert (info->gr <= MIPS_LAST_ARG_REG);
982 ainfo->storage = ArgInIReg;
983 ainfo->reg = info->gr;
984 info->gr += 1;
985 info->gr_passed = TRUE;
989 static void
990 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
991 /* First, see if we need to drop onto the stack */
992 if (!info->on_stack) {
993 if (info->gr > MIPS_LAST_ARG_REG)
994 args_onto_stack (info);
995 else if (info->fr > MIPS_LAST_FPARG_REG)
996 args_onto_stack (info);
999 /* Now, place the argument */
1000 if (info->on_stack) {
1001 ainfo->storage = ArgOnStack;
1002 ainfo->reg = mips_sp; /* in the caller */
1003 ainfo->offset = info->stack_size;
1004 info->stack_size += FREG_SIZE;
1006 else {
1007 ainfo->storage = ArgInFReg;
1008 ainfo->reg = info->fr;
1009 info->fr += 1;
1010 /* FP and GP slots do not overlap */
1011 info->gr += 1;
1015 static void
1016 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
1017 /* First, see if we need to drop onto the stack */
1018 if (!info->on_stack) {
1019 if (info->gr > MIPS_LAST_ARG_REG)
1020 args_onto_stack (info);
1021 else if (info->fr > MIPS_LAST_FPARG_REG)
1022 args_onto_stack (info);
1025 /* Now, place the argument */
1026 if (info->on_stack) {
1027 g_assert(info->stack_size % 4 == 0);
1028 info->stack_size += (info->stack_size % 8);
1030 ainfo->storage = ArgOnStack;
1031 ainfo->reg = mips_sp; /* in the caller */
1032 ainfo->offset = info->stack_size;
1033 info->stack_size += FREG_SIZE;
1035 else {
1036 ainfo->storage = ArgInFReg;
1037 ainfo->reg = info->fr;
1038 info->fr += 1;
1039 /* FP and GP slots do not overlap */
1040 info->gr += 1;
1043 #endif
1045 static CallInfo*
1046 get_call_info (MonoGenericSharingContext *gsctx, MonoMemPool *mp, MonoMethodSignature *sig)
1048 guint i;
1049 int n = sig->hasthis + sig->param_count;
1050 int pstart;
1051 MonoType* simpletype;
1052 CallInfo *cinfo;
1053 gboolean is_pinvoke = sig->pinvoke;
1055 if (mp)
1056 cinfo = mono_mempool_alloc0 (mp, sizeof (CallInfo) + (sizeof (ArgInfo) * n));
1057 else
1058 cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
1060 cinfo->fr = MIPS_FIRST_FPARG_REG;
1061 cinfo->gr = MIPS_FIRST_ARG_REG;
1062 cinfo->stack_size = 0;
1064 DEBUG(printf("calculate_sizes\n"));
1066 cinfo->vtype_retaddr = MONO_TYPE_ISSTRUCT (sig->ret) ? TRUE : FALSE;
1067 pstart = 0;
1068 n = 0;
1069 #if 0
1070 /* handle returning a struct */
1071 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1072 cinfo->struct_ret = cinfo->gr;
1073 add_int32_arg (cinfo, &cinfo->ret);
1076 if (sig->hasthis) {
1077 add_int32_arg (cinfo, cinfo->args + n);
1078 n++;
1080 #else
1082 * To simplify get_this_arg_reg () and LLVM integration, emit the vret arg after
1083 * the first argument, allowing 'this' to be always passed in the first arg reg.
1084 * Also do this if the first argument is a reference type, since virtual calls
1085 * are sometimes made using calli without sig->hasthis set, like in the delegate
1086 * invoke wrappers.
1088 if (cinfo->vtype_retaddr && !is_pinvoke && (sig->hasthis || (sig->param_count > 0 && MONO_TYPE_IS_REFERENCE (mini_type_get_underlying_type (gsctx, sig->params [0]))))) {
1089 if (sig->hasthis) {
1090 add_int32_arg (cinfo, cinfo->args + n);
1091 n ++;
1092 } else {
1093 add_int32_arg (cinfo, cinfo->args + sig->hasthis);
1094 pstart = 1;
1095 n ++;
1097 add_int32_arg (cinfo, &cinfo->ret);
1098 cinfo->struct_ret = cinfo->ret.reg;
1099 } else {
1100 /* this */
1101 if (sig->hasthis) {
1102 add_int32_arg (cinfo, cinfo->args + n);
1103 n ++;
1106 if (cinfo->vtype_retaddr) {
1107 add_int32_arg (cinfo, &cinfo->ret);
1108 cinfo->struct_ret = cinfo->ret.reg;
1111 #endif
1113 DEBUG(printf("params: %d\n", sig->param_count));
1114 for (i = pstart; i < sig->param_count; ++i) {
1115 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1116 /* Prevent implicit arguments and sig_cookie from
1117 being passed in registers */
1118 args_onto_stack (cinfo);
1119 /* Emit the signature cookie just before the implicit arguments */
1120 add_int32_arg (cinfo, &cinfo->sig_cookie);
1122 DEBUG(printf("param %d: ", i));
1123 simpletype = mini_type_get_underlying_type (gsctx, sig->params [i]);
1124 switch (simpletype->type) {
1125 case MONO_TYPE_BOOLEAN:
1126 case MONO_TYPE_I1:
1127 case MONO_TYPE_U1:
1128 DEBUG(printf("1 byte\n"));
1129 cinfo->args [n].size = 1;
1130 add_int32_arg (cinfo, &cinfo->args[n]);
1131 n++;
1132 break;
1133 case MONO_TYPE_CHAR:
1134 case MONO_TYPE_I2:
1135 case MONO_TYPE_U2:
1136 DEBUG(printf("2 bytes\n"));
1137 cinfo->args [n].size = 2;
1138 add_int32_arg (cinfo, &cinfo->args[n]);
1139 n++;
1140 break;
1141 case MONO_TYPE_I4:
1142 case MONO_TYPE_U4:
1143 DEBUG(printf("4 bytes\n"));
1144 cinfo->args [n].size = 4;
1145 add_int32_arg (cinfo, &cinfo->args[n]);
1146 n++;
1147 break;
1148 case MONO_TYPE_I:
1149 case MONO_TYPE_U:
1150 case MONO_TYPE_PTR:
1151 case MONO_TYPE_FNPTR:
1152 case MONO_TYPE_CLASS:
1153 case MONO_TYPE_OBJECT:
1154 case MONO_TYPE_STRING:
1155 case MONO_TYPE_SZARRAY:
1156 case MONO_TYPE_ARRAY:
1157 cinfo->args [n].size = sizeof (gpointer);
1158 add_int32_arg (cinfo, &cinfo->args[n]);
1159 n++;
1160 break;
1161 case MONO_TYPE_GENERICINST:
1162 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1163 cinfo->args [n].size = sizeof (gpointer);
1164 add_int32_arg (cinfo, &cinfo->args[n]);
1165 n++;
1166 break;
1168 /* Fall through */
1169 case MONO_TYPE_TYPEDBYREF:
1170 case MONO_TYPE_VALUETYPE: {
1171 int j;
1172 int nwords = 0;
1173 int has_offset = FALSE;
1174 ArgInfo dummy_arg;
1175 gint size, alignment;
1176 MonoClass *klass;
1178 if (simpletype->type == MONO_TYPE_TYPEDBYREF) {
1179 size = sizeof (MonoTypedRef);
1180 alignment = sizeof (gpointer);
1181 } else {
1182 klass = mono_class_from_mono_type (sig->params [i]);
1183 if (is_pinvoke)
1184 size = mono_class_native_size (klass, NULL);
1185 else
1186 size = mono_class_value_size (klass, NULL);
1187 alignment = mono_class_min_align (klass);
1189 #if MIPS_PASS_STRUCTS_BY_VALUE
1190 /* Need to do alignment if struct contains long or double */
1191 if (alignment > 4) {
1192 /* Drop onto stack *before* looking at
1193 stack_size, if required. */
1194 if (!cinfo->on_stack && cinfo->gr > MIPS_LAST_ARG_REG)
1195 args_onto_stack (cinfo);
1196 if (cinfo->stack_size & (alignment - 1)) {
1197 add_int32_arg (cinfo, &dummy_arg);
1199 g_assert (!(cinfo->stack_size & (alignment - 1)));
1202 #if 0
1203 g_printf ("valuetype struct size=%d offset=%d align=%d\n",
1204 mono_class_native_size (sig->params [i]->data.klass, NULL),
1205 cinfo->stack_size, alignment);
1206 #endif
1207 nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
1208 g_assert (cinfo->args [n].size == 0);
1209 g_assert (cinfo->args [n].vtsize == 0);
1210 for (j = 0; j < nwords; ++j) {
1211 if (j == 0) {
1212 add_int32_arg (cinfo, &cinfo->args [n]);
1213 if (cinfo->on_stack)
1214 has_offset = TRUE;
1215 } else {
1216 add_int32_arg (cinfo, &dummy_arg);
1217 if (!has_offset && cinfo->on_stack) {
1218 cinfo->args [n].offset = dummy_arg.offset;
1219 has_offset = TRUE;
1222 if (cinfo->on_stack)
1223 cinfo->args [n].vtsize += 1;
1224 else
1225 cinfo->args [n].size += 1;
1227 //g_printf ("\tstack_size=%d vtsize=%d\n", cinfo->args [n].size, cinfo->args[n].vtsize);
1228 cinfo->args [n].storage = ArgStructByVal;
1229 #else
1230 add_int32_arg (cinfo, &cinfo->args[n]);
1231 cinfo->args [n].storage = ArgStructByAddr;
1232 #endif
1233 n++;
1234 break;
1236 case MONO_TYPE_U8:
1237 case MONO_TYPE_I8:
1238 DEBUG(printf("8 bytes\n"));
1239 cinfo->args [n].size = 8;
1240 add_int64_arg (cinfo, &cinfo->args[n]);
1241 n++;
1242 break;
1243 case MONO_TYPE_R4:
1244 DEBUG(printf("R4\n"));
1245 cinfo->args [n].size = 4;
1246 add_float32_arg (cinfo, &cinfo->args[n]);
1247 n++;
1248 break;
1249 case MONO_TYPE_R8:
1250 DEBUG(printf("R8\n"));
1251 cinfo->args [n].size = 8;
1252 add_float64_arg (cinfo, &cinfo->args[n]);
1253 n++;
1254 break;
1255 default:
1256 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
1260 /* Handle the case where there are no implicit arguments */
1261 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1262 /* Prevent implicit arguments and sig_cookie from
1263 being passed in registers */
1264 args_onto_stack (cinfo);
1265 /* Emit the signature cookie just before the implicit arguments */
1266 add_int32_arg (cinfo, &cinfo->sig_cookie);
1270 simpletype = mini_type_get_underlying_type (gsctx, sig->ret);
1271 switch (simpletype->type) {
1272 case MONO_TYPE_BOOLEAN:
1273 case MONO_TYPE_I1:
1274 case MONO_TYPE_U1:
1275 case MONO_TYPE_I2:
1276 case MONO_TYPE_U2:
1277 case MONO_TYPE_CHAR:
1278 case MONO_TYPE_I4:
1279 case MONO_TYPE_U4:
1280 case MONO_TYPE_I:
1281 case MONO_TYPE_U:
1282 case MONO_TYPE_PTR:
1283 case MONO_TYPE_FNPTR:
1284 case MONO_TYPE_CLASS:
1285 case MONO_TYPE_OBJECT:
1286 case MONO_TYPE_SZARRAY:
1287 case MONO_TYPE_ARRAY:
1288 case MONO_TYPE_STRING:
1289 cinfo->ret.reg = mips_v0;
1290 break;
1291 case MONO_TYPE_U8:
1292 case MONO_TYPE_I8:
1293 cinfo->ret.reg = mips_v0;
1294 break;
1295 case MONO_TYPE_R4:
1296 case MONO_TYPE_R8:
1297 cinfo->ret.reg = mips_f0;
1298 cinfo->ret.storage = ArgInFReg;
1299 break;
1300 case MONO_TYPE_GENERICINST:
1301 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1302 cinfo->ret.reg = mips_v0;
1303 break;
1305 break;
1306 case MONO_TYPE_VALUETYPE:
1307 case MONO_TYPE_TYPEDBYREF:
1308 break;
1309 case MONO_TYPE_VOID:
1310 break;
1311 default:
1312 g_error ("Can't handle as return value 0x%x", sig->ret->type);
1316 /* align stack size to 16 */
1317 cinfo->stack_size = (cinfo->stack_size + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1319 cinfo->stack_usage = cinfo->stack_size;
1320 return cinfo;
1323 static gboolean
1324 debug_omit_fp (void)
1326 #if 0
1327 return mono_debug_count ();
1328 #else
1329 return TRUE;
1330 #endif
1334 * mono_arch_compute_omit_fp:
1336 * Determine whenever the frame pointer can be eliminated.
1338 static void
1339 mono_arch_compute_omit_fp (MonoCompile *cfg)
1341 MonoMethodSignature *sig;
1342 MonoMethodHeader *header;
1343 int i, locals_size;
1344 CallInfo *cinfo;
1346 if (cfg->arch.omit_fp_computed)
1347 return;
1349 header = cfg->header;
1351 sig = mono_method_signature (cfg->method);
1353 if (!cfg->arch.cinfo)
1354 cfg->arch.cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
1355 cinfo = cfg->arch.cinfo;
1358 * FIXME: Remove some of the restrictions.
1360 cfg->arch.omit_fp = TRUE;
1361 cfg->arch.omit_fp_computed = TRUE;
1363 if (cfg->disable_omit_fp)
1364 cfg->arch.omit_fp = FALSE;
1365 if (!debug_omit_fp ())
1366 cfg->arch.omit_fp = FALSE;
1367 if (cfg->method->save_lmf)
1368 cfg->arch.omit_fp = FALSE;
1369 if (cfg->flags & MONO_CFG_HAS_ALLOCA)
1370 cfg->arch.omit_fp = FALSE;
1371 if (header->num_clauses)
1372 cfg->arch.omit_fp = FALSE;
1373 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
1374 cfg->arch.omit_fp = FALSE;
1375 if ((mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method)) ||
1376 (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE))
1377 cfg->arch.omit_fp = FALSE;
1379 * On MIPS, fp points to the bottom of the frame, so it can be eliminated even if
1380 * there are stack arguments.
1383 if (cinfo->stack_usage)
1384 cfg->arch.omit_fp = FALSE;
1387 locals_size = 0;
1388 for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
1389 MonoInst *ins = cfg->varinfo [i];
1390 int ialign;
1392 locals_size += mono_type_size (ins->inst_vtype, &ialign);
1395 //printf ("D: %s %d\n", cfg->method->name, cfg->arch.omit_fp);
1399 * Set var information according to the calling convention. mips version.
1400 * The locals var stuff should most likely be split in another method.
1402 void
1403 mono_arch_allocate_vars (MonoCompile *cfg)
1405 MonoMethodSignature *sig;
1406 MonoMethodHeader *header;
1407 MonoInst *inst;
1408 int i, offset, size, align, curinst;
1409 int frame_reg = mips_sp;
1410 guint32 iregs_to_save = 0;
1411 #if SAVE_FP_REGS
1412 guint32 fregs_to_restore;
1413 #endif
1414 CallInfo *cinfo;
1416 sig = mono_method_signature (cfg->method);
1418 if (!cfg->arch.cinfo)
1419 cfg->arch.cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
1420 cinfo = cfg->arch.cinfo;
1422 mono_arch_compute_omit_fp (cfg);
1424 /* spill down, we'll fix it in a separate pass */
1425 // cfg->flags |= MONO_CFG_HAS_SPILLUP;
1427 /* allow room for the vararg method args: void* and long/double */
1428 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1429 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1431 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1432 * call convs needs to be handled this way.
1434 if (cfg->flags & MONO_CFG_HAS_VARARGS)
1435 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1437 /* gtk-sharp and other broken code will dllimport vararg functions even with
1438 * non-varargs signatures. Since there is little hope people will get this right
1439 * we assume they won't.
1441 if (cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1442 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1444 /* a0-a3 always present */
1445 cfg->param_area = MAX (cfg->param_area, MIPS_STACK_PARAM_OFFSET);
1447 header = cfg->header;
1449 if (cfg->arch.omit_fp)
1450 frame_reg = mips_sp;
1451 else
1452 frame_reg = mips_fp;
1453 cfg->frame_reg = frame_reg;
1454 if (frame_reg != mips_sp) {
1455 cfg->used_int_regs |= 1 << frame_reg;
1458 offset = 0;
1459 curinst = 0;
1460 if (!MONO_TYPE_ISSTRUCT (sig->ret)) {
1461 /* FIXME: handle long and FP values */
1462 switch (mini_type_get_underlying_type (cfg->generic_sharing_context, sig->ret)->type) {
1463 case MONO_TYPE_VOID:
1464 break;
1465 case MONO_TYPE_R4:
1466 case MONO_TYPE_R8:
1467 cfg->ret->opcode = OP_REGVAR;
1468 cfg->ret->inst_c0 = cfg->ret->dreg = mips_f0;
1469 break;
1470 default:
1471 cfg->ret->opcode = OP_REGVAR;
1472 cfg->ret->inst_c0 = mips_v0;
1473 break;
1476 /* Space for outgoing parameters, including a0-a3 */
1477 offset += cfg->param_area;
1479 /* allow room to save the return value (if it's a struct) */
1480 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1481 offset += 8;
1483 /* Now handle the local variables */
1485 curinst = cfg->locals_start;
1486 for (i = curinst; i < cfg->num_varinfo; ++i) {
1487 inst = cfg->varinfo [i];
1488 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
1489 continue;
1491 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
1492 * pinvoke wrappers when they call functions returning structure
1494 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
1495 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), (unsigned int *) &align);
1496 else
1497 size = mono_type_size (inst->inst_vtype, &align);
1499 offset += align - 1;
1500 offset &= ~(align - 1);
1501 inst->inst_offset = offset;
1502 inst->opcode = OP_REGOFFSET;
1503 inst->inst_basereg = frame_reg;
1504 offset += size;
1505 // g_print ("allocating local %d to %d\n", i, inst->inst_offset);
1508 /* Space for LMF (if needed) */
1509 if (cfg->method->save_lmf) {
1510 /* align the offset to 16 bytes */
1511 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1512 cfg->arch.lmf_offset = offset;
1513 offset += sizeof (MonoLMF);
1516 if (sig->call_convention == MONO_CALL_VARARG) {
1517 size = 4;
1518 align = 4;
1520 /* Allocate a local slot to hold the sig cookie address */
1521 offset += align - 1;
1522 offset &= ~(align - 1);
1523 cfg->sig_cookie = offset;
1524 offset += size;
1527 offset += SIZEOF_REGISTER - 1;
1528 offset &= ~(SIZEOF_REGISTER - 1);
1530 /* Space for saved registers */
1531 cfg->arch.iregs_offset = offset;
1532 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
1533 if (iregs_to_save) {
1534 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
1535 if (iregs_to_save & (1 << i)) {
1536 offset += SIZEOF_REGISTER;
1541 /* saved float registers */
1542 #if SAVE_FP_REGS
1543 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
1544 if (fregs_to_restore) {
1545 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
1546 if (fregs_to_restore & (1 << i)) {
1547 offset += sizeof(double);
1551 #endif
1553 #if _MIPS_SIM == _ABIO32
1554 /* Now add space for saving the ra */
1555 offset += SIZEOF_VOID_P;
1557 /* change sign? */
1558 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1559 cfg->stack_offset = offset;
1560 cfg->arch.local_alloc_offset = cfg->stack_offset;
1561 #endif
1564 * Now allocate stack slots for the int arg regs (a0 - a3)
1565 * On MIPS o32, these are just above the incoming stack pointer
1566 * Even if the arg has been assigned to a regvar, it gets a stack slot
1569 /* Return struct-by-value results in a hidden first argument */
1570 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1571 cfg->vret_addr->opcode = OP_REGOFFSET;
1572 cfg->vret_addr->inst_c0 = mips_a0;
1573 cfg->vret_addr->inst_offset = offset;
1574 cfg->vret_addr->inst_basereg = frame_reg;
1575 offset += SIZEOF_REGISTER;
1578 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
1579 inst = cfg->args [i];
1580 if (inst->opcode != OP_REGVAR) {
1581 MonoType *arg_type;
1583 if (sig->hasthis && (i == 0))
1584 arg_type = &mono_defaults.object_class->byval_arg;
1585 else
1586 arg_type = sig->params [i - sig->hasthis];
1588 inst->opcode = OP_REGOFFSET;
1589 size = mono_type_size (arg_type, &align);
1591 if (size < SIZEOF_REGISTER) {
1592 size = SIZEOF_REGISTER;
1593 align = SIZEOF_REGISTER;
1595 inst->inst_basereg = frame_reg;
1596 offset = (offset + align - 1) & ~(align - 1);
1597 inst->inst_offset = offset;
1598 offset += size;
1599 if (cfg->verbose_level > 1)
1600 printf ("allocating param %d to fp[%d]\n", i, inst->inst_offset);
1602 else {
1603 #if _MIPS_SIM == _ABIO32
1604 /* o32: Even a0-a3 get stack slots */
1605 size = SIZEOF_REGISTER;
1606 align = SIZEOF_REGISTER;
1607 inst->inst_basereg = frame_reg;
1608 offset = (offset + align - 1) & ~(align - 1);
1609 inst->inst_offset = offset;
1610 offset += size;
1611 if (cfg->verbose_level > 1)
1612 printf ("allocating param %d to fp[%d]\n", i, inst->inst_offset);
1613 #endif
1616 #if _MIPS_SIM == _ABIN32
1617 /* Now add space for saving the ra */
1618 offset += SIZEOF_VOID_P;
1620 /* change sign? */
1621 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1622 cfg->stack_offset = offset;
1623 cfg->arch.local_alloc_offset = cfg->stack_offset;
1624 #endif
1627 void
1628 mono_arch_create_vars (MonoCompile *cfg)
1630 MonoMethodSignature *sig;
1632 sig = mono_method_signature (cfg->method);
1634 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1635 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1636 if (G_UNLIKELY (cfg->verbose_level > 1)) {
1637 printf ("vret_addr = ");
1638 mono_print_ins (cfg->vret_addr);
1643 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1644 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1648 * take the arguments and generate the arch-specific
1649 * instructions to properly call the function in call.
1650 * This includes pushing, moving arguments to the right register
1651 * etc.
1652 * Issue: who does the spilling if needed, and when?
1654 static void
1655 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1657 MonoMethodSignature *tmp_sig;
1658 MonoInst *sig_arg;
1660 if (call->tail_call)
1661 NOT_IMPLEMENTED;
1663 /* FIXME: Add support for signature tokens to AOT */
1664 cfg->disable_aot = TRUE;
1667 * mono_ArgIterator_Setup assumes the signature cookie is
1668 * passed first and all the arguments which were before it are
1669 * passed on the stack after the signature. So compensate by
1670 * passing a different signature.
1672 tmp_sig = mono_metadata_signature_dup (call->signature);
1673 tmp_sig->param_count -= call->signature->sentinelpos;
1674 tmp_sig->sentinelpos = 0;
1675 memcpy (tmp_sig->params, call->signature->params + call->signature->sentinelpos, tmp_sig->param_count * sizeof (MonoType*));
1677 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
1678 sig_arg->dreg = mono_alloc_ireg (cfg);
1679 sig_arg->inst_p0 = tmp_sig;
1680 MONO_ADD_INS (cfg->cbb, sig_arg);
1682 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_sp, cinfo->sig_cookie.offset, sig_arg->dreg);
1685 void
1686 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1688 MonoInst *in, *ins;
1689 MonoMethodSignature *sig;
1690 int i, n;
1691 CallInfo *cinfo;
1692 int is_virtual = 0;
1694 sig = call->signature;
1695 n = sig->param_count + sig->hasthis;
1697 cinfo = get_call_info (NULL, cfg->mempool, sig);
1698 if (cinfo->struct_ret)
1699 call->used_iregs |= 1 << cinfo->struct_ret;
1701 for (i = 0; i < n; ++i) {
1702 ArgInfo *ainfo = cinfo->args + i;
1703 MonoType *t;
1705 if (i >= sig->hasthis)
1706 t = sig->params [i - sig->hasthis];
1707 else
1708 t = &mono_defaults.int_class->byval_arg;
1709 t = mini_type_get_underlying_type (cfg->generic_sharing_context, t);
1711 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1712 /* Emit the signature cookie just before the implicit arguments */
1713 emit_sig_cookie (cfg, call, cinfo);
1716 if (is_virtual && i == 0) {
1717 /* the argument will be attached to the call instrucion */
1718 in = call->args [i];
1719 call->used_iregs |= 1 << ainfo->reg;
1720 continue;
1722 in = call->args [i];
1723 if (ainfo->storage == ArgInIReg) {
1724 #if SIZEOF_REGISTER == 4
1725 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1726 MONO_INST_NEW (cfg, ins, OP_MOVE);
1727 ins->dreg = mono_alloc_ireg (cfg);
1728 ins->sreg1 = in->dreg + 1;
1729 MONO_ADD_INS (cfg->cbb, ins);
1730 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + ls_word_idx, FALSE);
1732 MONO_INST_NEW (cfg, ins, OP_MOVE);
1733 ins->dreg = mono_alloc_ireg (cfg);
1734 ins->sreg1 = in->dreg + 2;
1735 MONO_ADD_INS (cfg->cbb, ins);
1736 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + ms_word_idx, FALSE);
1737 } else
1738 #endif
1739 if (!t->byref && (t->type == MONO_TYPE_R4)) {
1740 int freg;
1742 #if PROMOTE_R4_TO_R8
1743 /* ??? - convert to single first? */
1744 MONO_INST_NEW (cfg, ins, OP_MIPS_CVTSD);
1745 ins->dreg = mono_alloc_freg (cfg);
1746 ins->sreg1 = in->dreg;
1747 MONO_ADD_INS (cfg->cbb, ins);
1748 freg = ins->dreg;
1749 #else
1750 freg = in->dreg;
1751 #endif
1752 /* trying to load float value into int registers */
1753 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1S);
1754 ins->dreg = mono_alloc_ireg (cfg);
1755 ins->sreg1 = freg;
1756 MONO_ADD_INS (cfg->cbb, ins);
1757 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1758 } else if (!t->byref && (t->type == MONO_TYPE_R8)) {
1759 /* trying to load float value into int registers */
1760 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1D);
1761 ins->dreg = mono_alloc_ireg (cfg);
1762 ins->sreg1 = in->dreg;
1763 MONO_ADD_INS (cfg->cbb, ins);
1764 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1765 } else {
1766 MONO_INST_NEW (cfg, ins, OP_MOVE);
1767 ins->dreg = mono_alloc_ireg (cfg);
1768 ins->sreg1 = in->dreg;
1769 MONO_ADD_INS (cfg->cbb, ins);
1770 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1772 } else if (ainfo->storage == ArgStructByAddr) {
1773 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1774 ins->opcode = OP_OUTARG_VT;
1775 ins->sreg1 = in->dreg;
1776 ins->klass = in->klass;
1777 ins->inst_p0 = call;
1778 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1779 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1780 MONO_ADD_INS (cfg->cbb, ins);
1781 } else if (ainfo->storage == ArgStructByVal) {
1782 /* this is further handled in mono_arch_emit_outarg_vt () */
1783 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1784 ins->opcode = OP_OUTARG_VT;
1785 ins->sreg1 = in->dreg;
1786 ins->klass = in->klass;
1787 ins->inst_p0 = call;
1788 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1789 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1790 MONO_ADD_INS (cfg->cbb, ins);
1791 } else if (ainfo->storage == ArgOnStack) {
1792 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1793 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1794 } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1795 if (t->type == MONO_TYPE_R8)
1796 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1797 else
1798 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1799 } else {
1800 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1802 } else if (ainfo->storage == ArgInFReg) {
1803 if (t->type == MONO_TYPE_VALUETYPE) {
1804 /* this is further handled in mono_arch_emit_outarg_vt () */
1805 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1806 ins->opcode = OP_OUTARG_VT;
1807 ins->sreg1 = in->dreg;
1808 ins->klass = in->klass;
1809 ins->inst_p0 = call;
1810 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1811 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1812 MONO_ADD_INS (cfg->cbb, ins);
1814 cfg->flags |= MONO_CFG_HAS_FPOUT;
1815 } else {
1816 int dreg = mono_alloc_freg (cfg);
1818 if (ainfo->size == 4) {
1819 MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, dreg, in->dreg);
1820 } else {
1821 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1822 ins->dreg = dreg;
1823 ins->sreg1 = in->dreg;
1824 MONO_ADD_INS (cfg->cbb, ins);
1827 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1828 cfg->flags |= MONO_CFG_HAS_FPOUT;
1830 } else {
1831 g_assert_not_reached ();
1835 /* Handle the case where there are no implicit arguments */
1836 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1837 emit_sig_cookie (cfg, call, cinfo);
1839 if (cinfo->struct_ret) {
1840 MonoInst *vtarg;
1842 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1843 vtarg->sreg1 = call->vret_var->dreg;
1844 vtarg->dreg = mono_alloc_preg (cfg);
1845 MONO_ADD_INS (cfg->cbb, vtarg);
1847 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1849 #if 0
1851 * Reverse the call->out_args list.
1854 MonoInst *prev = NULL, *list = call->out_args, *next;
1855 while (list) {
1856 next = list->next;
1857 list->next = prev;
1858 prev = list;
1859 list = next;
1861 call->out_args = prev;
1863 #endif
1864 call->stack_usage = cinfo->stack_usage;
1865 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1866 #if _MIPS_SIM == _ABIO32
1867 /* a0-a3 always present */
1868 cfg->param_area = MAX (cfg->param_area, 4 * SIZEOF_REGISTER);
1869 #endif
1870 cfg->param_area = (cfg->param_area + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1871 cfg->flags |= MONO_CFG_HAS_CALLS;
1873 * should set more info in call, such as the stack space
1874 * used by the args that needs to be added back to esp
1878 void
1879 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1881 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1882 ArgInfo *ainfo = ins->inst_p1;
1883 int ovf_size = ainfo->vtsize;
1884 int doffset = ainfo->offset;
1885 int i, soffset, dreg;
1887 if (ainfo->storage == ArgStructByVal) {
1888 #if 0
1889 if (cfg->verbose_level > 0) {
1890 char* nm = mono_method_full_name (cfg->method, TRUE);
1891 g_print ("Method %s outarg_vt struct doffset=%d ainfo->size=%d ovf_size=%d\n",
1892 nm, doffset, ainfo->size, ovf_size);
1893 g_free (nm);
1895 #endif
1897 soffset = 0;
1898 for (i = 0; i < ainfo->size; ++i) {
1899 dreg = mono_alloc_ireg (cfg);
1900 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1901 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1902 soffset += SIZEOF_REGISTER;
1904 if (ovf_size != 0) {
1905 mini_emit_memcpy (cfg, mips_sp, doffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
1907 } else if (ainfo->storage == ArgInFReg) {
1908 int tmpr = mono_alloc_freg (cfg);
1910 if (ainfo->size == 4)
1911 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1912 else
1913 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1914 dreg = mono_alloc_freg (cfg);
1915 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1916 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1917 } else {
1918 MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
1919 MonoInst *load;
1920 guint32 size;
1922 /* FIXME: alignment? */
1923 if (call->signature->pinvoke) {
1924 size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
1925 vtcopy->backend.is_pinvoke = 1;
1926 } else {
1927 size = mini_type_stack_size (cfg->generic_sharing_context, &src->klass->byval_arg, NULL);
1929 if (size > 0)
1930 g_assert (ovf_size > 0);
1932 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1933 mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, size, 0);
1935 if (ainfo->offset)
1936 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_at, ainfo->offset, load->dreg);
1937 else
1938 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1942 void
1943 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1945 MonoType *ret = mini_type_get_underlying_type (cfg->generic_sharing_context,
1946 mono_method_signature (method)->ret);
1948 if (!ret->byref) {
1949 #if (SIZEOF_REGISTER == 4)
1950 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1951 MonoInst *ins;
1953 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1954 ins->sreg1 = val->dreg + 1;
1955 ins->sreg2 = val->dreg + 2;
1956 MONO_ADD_INS (cfg->cbb, ins);
1957 return;
1959 #endif
1960 if (ret->type == MONO_TYPE_R8) {
1961 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1962 return;
1964 if (ret->type == MONO_TYPE_R4) {
1965 MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, cfg->ret->dreg, val->dreg);
1966 return;
1969 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1972 void
1973 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1975 MonoInst *ins, *n, *last_ins = NULL;
1977 if (cfg->verbose_level > 2)
1978 g_print ("Basic block %d peephole pass 1\n", bb->block_num);
1980 ins = bb->code;
1981 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1982 if (cfg->verbose_level > 2)
1983 mono_print_ins_index (0, ins);
1985 switch (ins->opcode) {
1986 #if 0
1987 case OP_LOAD_MEMBASE:
1988 case OP_LOADI4_MEMBASE:
1990 * OP_IADD reg2, reg1, const1
1991 * OP_LOAD_MEMBASE const2(reg2), reg3
1992 * ->
1993 * OP_LOAD_MEMBASE (const1+const2)(reg1), reg3
1995 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)){
1996 int const1 = last_ins->inst_imm;
1997 int const2 = ins->inst_offset;
1999 if (mips_is_imm16 (const1 + const2)) {
2000 ins->inst_basereg = last_ins->sreg1;
2001 ins->inst_offset = const1 + const2;
2004 break;
2005 #endif
2008 last_ins = ins;
2009 ins = ins->next;
2011 bb->last_ins = last_ins;
2014 void
2015 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
2017 MonoInst *ins, *n, *last_ins = NULL;
2018 ins = bb->code;
2020 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
2021 MonoInst *last_ins = ins->prev;
2023 switch (ins->opcode) {
2024 case OP_MUL_IMM:
2025 /* remove unnecessary multiplication with 1 */
2026 if (ins->inst_imm == 1) {
2027 if (ins->dreg != ins->sreg1) {
2028 ins->opcode = OP_MOVE;
2029 } else {
2030 MONO_DELETE_INS (bb, ins);
2031 continue;
2033 } else {
2034 int power2 = mono_is_power_of_two (ins->inst_imm);
2035 if (power2 > 0) {
2036 ins->opcode = OP_SHL_IMM;
2037 ins->inst_imm = power2;
2040 break;
2041 case OP_LOAD_MEMBASE:
2042 case OP_LOADI4_MEMBASE:
2044 * OP_STORE_MEMBASE_REG reg, offset(basereg)
2045 * OP_LOAD_MEMBASE offset(basereg), reg
2047 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
2048 || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
2049 ins->inst_basereg == last_ins->inst_destbasereg &&
2050 ins->inst_offset == last_ins->inst_offset) {
2051 if (ins->dreg == last_ins->sreg1) {
2052 MONO_DELETE_INS (bb, ins);
2053 continue;
2054 } else {
2055 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2056 ins->opcode = OP_MOVE;
2057 ins->sreg1 = last_ins->sreg1;
2059 break;
2062 * Note: reg1 must be different from the basereg in the second load
2063 * OP_LOAD_MEMBASE offset(basereg), reg1
2064 * OP_LOAD_MEMBASE offset(basereg), reg2
2065 * -->
2066 * OP_LOAD_MEMBASE offset(basereg), reg1
2067 * OP_MOVE reg1, reg2
2069 if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
2070 || last_ins->opcode == OP_LOAD_MEMBASE) &&
2071 ins->inst_basereg != last_ins->dreg &&
2072 ins->inst_basereg == last_ins->inst_basereg &&
2073 ins->inst_offset == last_ins->inst_offset) {
2075 if (ins->dreg == last_ins->dreg) {
2076 MONO_DELETE_INS (bb, ins);
2077 continue;
2078 } else {
2079 ins->opcode = OP_MOVE;
2080 ins->sreg1 = last_ins->dreg;
2083 //g_assert_not_reached ();
2084 break;
2086 #if 0
2088 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2089 * OP_LOAD_MEMBASE offset(basereg), reg
2090 * -->
2091 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2092 * OP_ICONST reg, imm
2094 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
2095 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
2096 ins->inst_basereg == last_ins->inst_destbasereg &&
2097 ins->inst_offset == last_ins->inst_offset) {
2098 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2099 ins->opcode = OP_ICONST;
2100 ins->inst_c0 = last_ins->inst_imm;
2101 g_assert_not_reached (); // check this rule
2102 break;
2104 #endif
2105 break;
2106 case OP_LOADU1_MEMBASE:
2107 case OP_LOADI1_MEMBASE:
2108 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
2109 ins->inst_basereg == last_ins->inst_destbasereg &&
2110 ins->inst_offset == last_ins->inst_offset) {
2111 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
2112 ins->sreg1 = last_ins->sreg1;
2114 break;
2115 case OP_LOADU2_MEMBASE:
2116 case OP_LOADI2_MEMBASE:
2117 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
2118 ins->inst_basereg == last_ins->inst_destbasereg &&
2119 ins->inst_offset == last_ins->inst_offset) {
2120 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
2121 ins->sreg1 = last_ins->sreg1;
2123 break;
2124 case OP_ICONV_TO_I4:
2125 case OP_ICONV_TO_U4:
2126 case OP_MOVE:
2127 ins->opcode = OP_MOVE;
2129 * OP_MOVE reg, reg
2131 if (ins->dreg == ins->sreg1) {
2132 MONO_DELETE_INS (bb, ins);
2133 continue;
2136 * OP_MOVE sreg, dreg
2137 * OP_MOVE dreg, sreg
2139 if (last_ins && last_ins->opcode == OP_MOVE &&
2140 ins->sreg1 == last_ins->dreg &&
2141 ins->dreg == last_ins->sreg1) {
2142 MONO_DELETE_INS (bb, ins);
2143 continue;
2145 break;
2147 last_ins = ins;
2148 ins = ins->next;
2150 bb->last_ins = last_ins;
2153 void
2154 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins)
2156 int tmp1 = -1;
2157 int tmp2 = -1;
2158 int tmp3 = -1;
2159 int tmp4 = -1;
2160 int tmp5 = -1;
2162 switch (ins->opcode) {
2163 #if 0
2164 case OP_LCOMPARE:
2165 case OP_LCOMPARE_IMM:
2166 mono_print_ins (ins);
2167 g_assert_not_reached ();
2168 #endif
2169 case OP_LADD:
2170 tmp1 = mono_alloc_ireg (cfg);
2171 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2172 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2173 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2174 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
2175 NULLIFY_INS(ins);
2176 break;
2178 case OP_LADD_IMM:
2179 tmp1 = mono_alloc_ireg (cfg);
2180 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
2181 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2182 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
2183 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
2184 NULLIFY_INS(ins);
2185 break;
2187 case OP_LSUB:
2188 tmp1 = mono_alloc_ireg (cfg);
2189 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2190 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2191 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2192 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2193 NULLIFY_INS(ins);
2194 break;
2196 case OP_LSUB_IMM:
2197 tmp1 = mono_alloc_ireg (cfg);
2198 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
2199 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2200 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
2201 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2202 NULLIFY_INS(ins);
2203 break;
2205 case OP_LMUL:
2206 case OP_LDIV:
2207 case OP_LDIV_UN:
2208 case OP_LREM:
2209 case OP_LREM_UN:
2210 case OP_LSHL:
2211 case OP_LSHR:
2212 case OP_LSHR_UN:
2213 mono_print_ins (ins);
2214 g_assert_not_reached ();
2216 case OP_LNEG:
2217 tmp1 = mono_alloc_ireg (cfg);
2218 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, mips_zero, ins->sreg1+1);
2219 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, mips_zero, ins->dreg+1);
2220 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, mips_zero, ins->sreg1+2);
2221 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2222 NULLIFY_INS(ins);
2223 break;
2225 #if 0
2226 case OP_LNOT:
2227 #endif
2228 #if 0
2229 case OP_LCONV_TO_I1:
2230 case OP_LCONV_TO_I2:
2231 case OP_LCONV_TO_I4:
2232 case OP_LCONV_TO_I8:
2233 case OP_LCONV_TO_R4:
2234 case OP_LCONV_TO_R8:
2235 case OP_LCONV_TO_U4:
2236 case OP_LCONV_TO_U8:
2237 case OP_LCONV_TO_U2:
2238 case OP_LCONV_TO_U1:
2239 case OP_LCONV_TO_I:
2240 case OP_LCONV_TO_OVF_I:
2241 case OP_LCONV_TO_OVF_U:
2242 #endif
2243 mono_print_ins (ins);
2244 g_assert_not_reached ();
2246 case OP_LADD_OVF:
2247 tmp1 = mono_alloc_ireg (cfg);
2248 tmp2 = mono_alloc_ireg (cfg);
2249 tmp3 = mono_alloc_ireg (cfg);
2250 tmp4 = mono_alloc_ireg (cfg);
2251 tmp5 = mono_alloc_ireg (cfg);
2253 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2255 /* tmp1 holds the carry from the low 32-bit to the high 32-bits */
2256 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->dreg+1, ins->sreg1+1);
2258 /* add the high 32-bits, and add in the carry from the low 32-bits */
2259 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2260 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp5, ins->dreg+2);
2262 /* Overflow happens if
2263 * neg + neg = pos or
2264 * pos + pos = neg
2265 * XOR of the high bits returns 0 if the signs match
2266 * XOR of that with the high bit of the result return 1 if overflow.
2269 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2270 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2272 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2273 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg+2, ins->sreg2+2);
2274 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp2, tmp2);
2276 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2277 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp3, tmp2, tmp1);
2278 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2280 /* Now, if (tmp4 == 0) then overflow */
2281 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp4, mips_zero, "OverflowException");
2282 NULLIFY_INS(ins);
2283 break;
2285 case OP_LADD_OVF_UN:
2286 tmp1 = mono_alloc_ireg (cfg);
2287 tmp2 = mono_alloc_ireg (cfg);
2289 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2290 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2291 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2292 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp1, ins->dreg+2);
2293 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->dreg+2, ins->sreg1+2);
2294 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2295 NULLIFY_INS(ins);
2296 break;
2298 case OP_LMUL_OVF:
2299 case OP_LMUL_OVF_UN:
2300 mono_print_ins (ins);
2301 g_assert_not_reached ();
2303 case OP_LSUB_OVF:
2304 tmp1 = mono_alloc_ireg (cfg);
2305 tmp2 = mono_alloc_ireg (cfg);
2306 tmp3 = mono_alloc_ireg (cfg);
2307 tmp4 = mono_alloc_ireg (cfg);
2308 tmp5 = mono_alloc_ireg (cfg);
2310 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2312 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->sreg1+1, ins->dreg+1);
2313 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2314 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp5);
2316 /* Overflow happens if
2317 * neg - pos = pos or
2318 * pos - neg = neg
2319 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2321 * tmp1 = (lhs ^ rhs)
2322 * tmp2 = (lhs ^ result)
2323 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2326 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2327 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1+2, ins->dreg+2);
2328 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp3, tmp2, tmp1);
2329 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2331 /* Now, if (tmp4 == 1) then overflow */
2332 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp4, mips_zero, "OverflowException");
2333 NULLIFY_INS(ins);
2334 break;
2336 case OP_LSUB_OVF_UN:
2337 tmp1 = mono_alloc_ireg (cfg);
2338 tmp2 = mono_alloc_ireg (cfg);
2340 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2341 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2342 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2343 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2345 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->sreg1+2, ins->dreg+2);
2346 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2347 NULLIFY_INS(ins);
2348 break;
2349 #if 0
2350 case OP_LCONV_TO_OVF_I1_UN:
2351 case OP_LCONV_TO_OVF_I2_UN:
2352 case OP_LCONV_TO_OVF_I4_UN:
2353 case OP_LCONV_TO_OVF_I8_UN:
2354 case OP_LCONV_TO_OVF_U1_UN:
2355 case OP_LCONV_TO_OVF_U2_UN:
2356 case OP_LCONV_TO_OVF_U4_UN:
2357 case OP_LCONV_TO_OVF_U8_UN:
2358 case OP_LCONV_TO_OVF_I_UN:
2359 case OP_LCONV_TO_OVF_U_UN:
2360 case OP_LCONV_TO_OVF_I1:
2361 case OP_LCONV_TO_OVF_U1:
2362 case OP_LCONV_TO_OVF_I2:
2363 case OP_LCONV_TO_OVF_U2:
2364 case OP_LCONV_TO_OVF_I4:
2365 case OP_LCONV_TO_OVF_U4:
2366 case OP_LCONV_TO_OVF_I8:
2367 case OP_LCONV_TO_OVF_U8:
2368 #endif
2369 case OP_LCEQ:
2370 case OP_LCGT:
2371 case OP_LCGT_UN:
2372 case OP_LCLT:
2373 case OP_LCLT_UN:
2374 #if 0
2375 case OP_LCONV_TO_R_UN:
2376 case OP_LCONV_TO_U:
2377 #endif
2378 case OP_LMUL_IMM:
2379 case OP_LSHL_IMM:
2380 case OP_LSHR_IMM:
2381 case OP_LSHR_UN_IMM:
2382 case OP_LDIV_IMM:
2383 case OP_LDIV_UN_IMM:
2384 case OP_LREM_IMM:
2385 case OP_LREM_UN_IMM:
2386 case OP_LBEQ:
2387 case OP_LBGE:
2388 case OP_LBGT:
2389 case OP_LBLE:
2390 case OP_LBLT:
2391 case OP_LBNE_UN:
2392 case OP_LBGE_UN:
2393 case OP_LBGT_UN:
2394 case OP_LBLE_UN:
2395 case OP_LBLT_UN:
2396 mono_print_ins (ins);
2397 g_assert_not_reached ();
2398 #if 0
2399 case OP_LCONV_TO_R8_2:
2400 case OP_LCONV_TO_R4_2:
2401 case OP_LCONV_TO_R_UN_2:
2402 #endif
2403 case OP_LCONV_TO_OVF_I4_2:
2404 tmp1 = mono_alloc_ireg (cfg);
2406 /* Overflows if reg2 != sign extension of reg1 */
2407 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp1, ins->sreg1, 31);
2408 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, ins->sreg2, tmp1, "OverflowException");
2409 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
2410 NULLIFY_INS(ins);
2411 break;
2413 case OP_LMIN_UN:
2414 case OP_LMAX_UN:
2415 case OP_LMIN:
2416 case OP_LMAX:
2417 mono_print_ins (ins);
2418 g_assert_not_reached ();
2420 default:
2421 break;
2425 void
2426 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
2428 int tmp1 = -1;
2429 int tmp2 = -1;
2430 int tmp3 = -1;
2431 int tmp4 = -1;
2432 int tmp5 = -1;
2434 switch (ins->opcode) {
2435 case OP_IADD_OVF:
2436 tmp1 = mono_alloc_ireg (cfg);
2437 tmp2 = mono_alloc_ireg (cfg);
2438 tmp3 = mono_alloc_ireg (cfg);
2439 tmp4 = mono_alloc_ireg (cfg);
2440 tmp5 = mono_alloc_ireg (cfg);
2442 /* add the operands */
2444 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2446 /* Overflow happens if
2447 * neg + neg = pos or
2448 * pos + pos = neg
2450 * (bit31s of operands match) AND (bit31 of operand != bit31 of result)
2451 * XOR of the high bit returns 0 if the signs match
2452 * XOR of that with the high bit of the result return 1 if overflow.
2455 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2456 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2458 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2459 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg, ins->sreg2);
2460 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp3, tmp2);
2462 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2463 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp4, tmp3, tmp1);
2465 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp5, tmp4, 31);
2467 /* Now, if (tmp5 == 0) then overflow */
2468 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp5, mips_zero, "OverflowException");
2469 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2470 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2471 NULLIFY_INS(ins);
2472 break;
2474 case OP_IADD_OVF_UN:
2475 tmp1 = mono_alloc_ireg (cfg);
2477 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2478 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg, ins->sreg1);
2479 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2480 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2481 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2482 NULLIFY_INS(ins);
2483 break;
2485 case OP_ISUB_OVF:
2486 tmp1 = mono_alloc_ireg (cfg);
2487 tmp2 = mono_alloc_ireg (cfg);
2488 tmp3 = mono_alloc_ireg (cfg);
2489 tmp4 = mono_alloc_ireg (cfg);
2490 tmp5 = mono_alloc_ireg (cfg);
2492 /* add the operands */
2494 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2496 /* Overflow happens if
2497 * neg - pos = pos or
2498 * pos - neg = neg
2499 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2501 * tmp1 = (lhs ^ rhs)
2502 * tmp2 = (lhs ^ result)
2503 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2506 /* tmp3 = 1 if the signs of the two inputs differ */
2507 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2508 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1, ins->dreg);
2509 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp3, tmp1, 0);
2510 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp4, tmp2, 0);
2511 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp5, tmp4, tmp3);
2513 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp5, mips_zero, "OverflowException");
2514 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2515 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2516 NULLIFY_INS(ins);
2517 break;
2519 case OP_ISUB_OVF_UN:
2520 tmp1 = mono_alloc_ireg (cfg);
2522 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2523 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1, ins->dreg);
2524 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2525 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2526 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2527 NULLIFY_INS(ins);
2528 break;
2532 static int
2533 map_to_reg_reg_op (int op)
2535 switch (op) {
2536 case OP_ADD_IMM:
2537 return OP_IADD;
2538 case OP_SUB_IMM:
2539 return OP_ISUB;
2540 case OP_AND_IMM:
2541 return OP_IAND;
2542 case OP_COMPARE_IMM:
2543 return OP_COMPARE;
2544 case OP_ICOMPARE_IMM:
2545 return OP_ICOMPARE;
2546 case OP_LCOMPARE_IMM:
2547 return OP_LCOMPARE;
2548 case OP_ADDCC_IMM:
2549 return OP_IADDCC;
2550 case OP_ADC_IMM:
2551 return OP_IADC;
2552 case OP_SUBCC_IMM:
2553 return OP_ISUBCC;
2554 case OP_SBB_IMM:
2555 return OP_ISBB;
2556 case OP_OR_IMM:
2557 return OP_IOR;
2558 case OP_XOR_IMM:
2559 return OP_IXOR;
2560 case OP_MUL_IMM:
2561 return OP_IMUL;
2562 case OP_LOAD_MEMBASE:
2563 return OP_LOAD_MEMINDEX;
2564 case OP_LOADI4_MEMBASE:
2565 return OP_LOADI4_MEMINDEX;
2566 case OP_LOADU4_MEMBASE:
2567 return OP_LOADU4_MEMINDEX;
2568 case OP_LOADU1_MEMBASE:
2569 return OP_LOADU1_MEMINDEX;
2570 case OP_LOADI2_MEMBASE:
2571 return OP_LOADI2_MEMINDEX;
2572 case OP_LOADU2_MEMBASE:
2573 return OP_LOADU2_MEMINDEX;
2574 case OP_LOADI1_MEMBASE:
2575 return OP_LOADI1_MEMINDEX;
2576 case OP_LOADR4_MEMBASE:
2577 return OP_LOADR4_MEMINDEX;
2578 case OP_LOADR8_MEMBASE:
2579 return OP_LOADR8_MEMINDEX;
2580 case OP_STOREI1_MEMBASE_REG:
2581 return OP_STOREI1_MEMINDEX;
2582 case OP_STOREI2_MEMBASE_REG:
2583 return OP_STOREI2_MEMINDEX;
2584 case OP_STOREI4_MEMBASE_REG:
2585 return OP_STOREI4_MEMINDEX;
2586 case OP_STORE_MEMBASE_REG:
2587 return OP_STORE_MEMINDEX;
2588 case OP_STORER4_MEMBASE_REG:
2589 return OP_STORER4_MEMINDEX;
2590 case OP_STORER8_MEMBASE_REG:
2591 return OP_STORER8_MEMINDEX;
2592 case OP_STORE_MEMBASE_IMM:
2593 return OP_STORE_MEMBASE_REG;
2594 case OP_STOREI1_MEMBASE_IMM:
2595 return OP_STOREI1_MEMBASE_REG;
2596 case OP_STOREI2_MEMBASE_IMM:
2597 return OP_STOREI2_MEMBASE_REG;
2598 case OP_STOREI4_MEMBASE_IMM:
2599 return OP_STOREI4_MEMBASE_REG;
2600 case OP_STOREI8_MEMBASE_IMM:
2601 return OP_STOREI8_MEMBASE_REG;
2603 return mono_op_imm_to_op (op);
2606 static int
2607 map_to_mips_op (int op)
2609 switch (op) {
2610 case OP_FBEQ:
2611 return OP_MIPS_FBEQ;
2612 case OP_FBGE:
2613 return OP_MIPS_FBGE;
2614 case OP_FBGT:
2615 return OP_MIPS_FBGT;
2616 case OP_FBLE:
2617 return OP_MIPS_FBLE;
2618 case OP_FBLT:
2619 return OP_MIPS_FBLT;
2620 case OP_FBNE_UN:
2621 return OP_MIPS_FBNE;
2622 case OP_FBGE_UN:
2623 return OP_MIPS_FBGE_UN;
2624 case OP_FBGT_UN:
2625 return OP_MIPS_FBGT_UN;
2626 case OP_FBLE_UN:
2627 return OP_MIPS_FBLE_UN;
2628 case OP_FBLT_UN:
2629 return OP_MIPS_FBLT_UN;
2631 case OP_FCEQ:
2632 case OP_FCGT:
2633 case OP_FCGT_UN:
2634 case OP_FCLT:
2635 case OP_FCLT_UN:
2636 default:
2637 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (op), __FUNCTION__);
2638 g_assert_not_reached ();
2642 #define NEW_INS(cfg,after,dest,op) do { \
2643 MONO_INST_NEW((cfg), (dest), (op)); \
2644 mono_bblock_insert_after_ins (bb, (after), (dest)); \
2645 } while (0)
2647 #define INS(pos,op,_dreg,_sreg1,_sreg2) do { \
2648 MonoInst *temp; \
2649 MONO_INST_NEW(cfg, temp, (op)); \
2650 mono_bblock_insert_after_ins (bb, (pos), temp); \
2651 temp->dreg = (_dreg); \
2652 temp->sreg1 = (_sreg1); \
2653 temp->sreg2 = (_sreg2); \
2654 pos = temp; \
2655 } while (0)
2657 #define INS_IMM(pos,op,_dreg,_sreg1,_imm) do { \
2658 MonoInst *temp; \
2659 MONO_INST_NEW(cfg, temp, (op)); \
2660 mono_bblock_insert_after_ins (bb, (pos), temp); \
2661 temp->dreg = (_dreg); \
2662 temp->sreg1 = (_sreg1); \
2663 temp->inst_c0 = (_imm); \
2664 pos = temp; \
2665 } while (0)
2668 * Remove from the instruction list the instructions that can't be
2669 * represented with very simple instructions with no register
2670 * requirements.
2672 void
2673 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2675 MonoInst *ins, *next, *temp, *last_ins = NULL;
2676 int imm;
2678 #if 1
2679 if (cfg->verbose_level > 2) {
2680 int idx = 0;
2682 g_print ("BASIC BLOCK %d (before lowering)\n", bb->block_num);
2683 MONO_BB_FOR_EACH_INS (bb, ins) {
2684 mono_print_ins_index (idx++, ins);
2688 #endif
2690 MONO_BB_FOR_EACH_INS (bb, ins) {
2691 loop_start:
2692 switch (ins->opcode) {
2693 case OP_COMPARE:
2694 case OP_ICOMPARE:
2695 case OP_LCOMPARE:
2696 next = ins->next;
2697 /* Branch opts can eliminate the branch */
2698 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2699 NULLIFY_INS(ins);
2700 break;
2702 break;
2704 case OP_COMPARE_IMM:
2705 case OP_ICOMPARE_IMM:
2706 case OP_LCOMPARE_IMM:
2707 next = ins->next;
2708 /* Branch opts can eliminate the branch */
2709 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2710 NULLIFY_INS(ins);
2711 break;
2713 if (ins->inst_imm) {
2714 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2715 temp->inst_c0 = ins->inst_imm;
2716 temp->dreg = mono_alloc_ireg (cfg);
2717 ins->sreg2 = temp->dreg;
2718 last_ins = temp;
2720 else {
2721 ins->sreg2 = mips_zero;
2723 if (ins->opcode == OP_COMPARE_IMM)
2724 ins->opcode = OP_COMPARE;
2725 else if (ins->opcode == OP_ICOMPARE_IMM)
2726 ins->opcode = OP_ICOMPARE;
2727 else if (ins->opcode == OP_LCOMPARE_IMM)
2728 ins->opcode = OP_LCOMPARE;
2729 goto loop_start;
2731 case OP_IDIV_UN_IMM:
2732 case OP_IDIV_IMM:
2733 case OP_IREM_IMM:
2734 case OP_IREM_UN_IMM:
2735 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2736 temp->inst_c0 = ins->inst_imm;
2737 temp->dreg = mono_alloc_ireg (cfg);
2738 ins->sreg2 = temp->dreg;
2739 if (ins->opcode == OP_IDIV_IMM)
2740 ins->opcode = OP_IDIV;
2741 else if (ins->opcode == OP_IREM_IMM)
2742 ins->opcode = OP_IREM;
2743 else if (ins->opcode == OP_IDIV_UN_IMM)
2744 ins->opcode = OP_IDIV_UN;
2745 else if (ins->opcode == OP_IREM_UN_IMM)
2746 ins->opcode = OP_IREM_UN;
2747 last_ins = temp;
2748 /* handle rem separately */
2749 goto loop_start;
2751 #if 0
2752 case OP_AND_IMM:
2753 case OP_OR_IMM:
2754 case OP_XOR_IMM:
2755 if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
2756 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2757 temp->inst_c0 = ins->inst_imm;
2758 temp->dreg = mono_alloc_ireg (cfg);
2759 ins->sreg2 = temp->dreg;
2760 ins->opcode = map_to_reg_reg_op (ins->opcode);
2762 break;
2763 #endif
2764 case OP_AND_IMM:
2765 case OP_IAND_IMM:
2766 case OP_OR_IMM:
2767 case OP_IOR_IMM:
2768 case OP_XOR_IMM:
2769 case OP_IXOR_IMM:
2770 /* unsigned 16 bit immediate */
2771 if (ins->inst_imm & 0xffff0000) {
2772 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2773 temp->inst_c0 = ins->inst_imm;
2774 temp->dreg = mono_alloc_ireg (cfg);
2775 ins->sreg2 = temp->dreg;
2776 ins->opcode = map_to_reg_reg_op (ins->opcode);
2778 break;
2780 case OP_IADD_IMM:
2781 case OP_ADD_IMM:
2782 case OP_ADDCC_IMM:
2783 /* signed 16 bit immediate */
2784 if (!mips_is_imm16 (ins->inst_imm)) {
2785 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2786 temp->inst_c0 = ins->inst_imm;
2787 temp->dreg = mono_alloc_ireg (cfg);
2788 ins->sreg2 = temp->dreg;
2789 ins->opcode = map_to_reg_reg_op (ins->opcode);
2791 break;
2793 case OP_SUB_IMM:
2794 case OP_ISUB_IMM:
2795 if (!mips_is_imm16 (-ins->inst_imm)) {
2796 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2797 temp->inst_c0 = ins->inst_imm;
2798 temp->dreg = mono_alloc_ireg (cfg);
2799 ins->sreg2 = temp->dreg;
2800 ins->opcode = map_to_reg_reg_op (ins->opcode);
2802 break;
2804 case OP_MUL_IMM:
2805 case OP_IMUL_IMM:
2806 if (ins->inst_imm == 1) {
2807 ins->opcode = OP_MOVE;
2808 break;
2810 if (ins->inst_imm == 0) {
2811 ins->opcode = OP_ICONST;
2812 ins->inst_c0 = 0;
2813 break;
2815 imm = mono_is_power_of_two (ins->inst_imm);
2816 if (imm > 0) {
2817 ins->opcode = OP_SHL_IMM;
2818 ins->inst_imm = imm;
2819 break;
2821 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2822 temp->inst_c0 = ins->inst_imm;
2823 temp->dreg = mono_alloc_ireg (cfg);
2824 ins->sreg2 = temp->dreg;
2825 ins->opcode = map_to_reg_reg_op (ins->opcode);
2826 break;
2828 case OP_LOCALLOC_IMM:
2829 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2830 temp->inst_c0 = ins->inst_imm;
2831 temp->dreg = mono_alloc_ireg (cfg);
2832 ins->sreg1 = temp->dreg;
2833 ins->opcode = OP_LOCALLOC;
2834 break;
2836 case OP_LOADR4_MEMBASE:
2837 case OP_STORER4_MEMBASE_REG:
2838 /* we can do two things: load the immed in a register
2839 * and use an indexed load, or see if the immed can be
2840 * represented as an ad_imm + a load with a smaller offset
2841 * that fits. We just do the first for now, optimize later.
2843 if (mips_is_imm16 (ins->inst_offset))
2844 break;
2845 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2846 temp->inst_c0 = ins->inst_offset;
2847 temp->dreg = mono_alloc_ireg (cfg);
2848 ins->sreg2 = temp->dreg;
2849 ins->opcode = map_to_reg_reg_op (ins->opcode);
2850 break;
2852 case OP_STORE_MEMBASE_IMM:
2853 case OP_STOREI1_MEMBASE_IMM:
2854 case OP_STOREI2_MEMBASE_IMM:
2855 case OP_STOREI4_MEMBASE_IMM:
2856 case OP_STOREI8_MEMBASE_IMM:
2857 if (!ins->inst_imm) {
2858 ins->sreg1 = mips_zero;
2859 ins->opcode = map_to_reg_reg_op (ins->opcode);
2861 else {
2862 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2863 temp->inst_c0 = ins->inst_imm;
2864 temp->dreg = mono_alloc_ireg (cfg);
2865 ins->sreg1 = temp->dreg;
2866 ins->opcode = map_to_reg_reg_op (ins->opcode);
2867 last_ins = temp;
2868 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2870 break;
2872 case OP_FCOMPARE:
2873 next = ins->next;
2874 /* Branch opts can eliminate the branch */
2875 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2876 NULLIFY_INS(ins);
2877 break;
2879 g_assert(next);
2882 * remap compare/branch and compare/set
2883 * to MIPS specific opcodes.
2885 next->opcode = map_to_mips_op (next->opcode);
2886 next->sreg1 = ins->sreg1;
2887 next->sreg2 = ins->sreg2;
2888 NULLIFY_INS(ins);
2889 break;
2891 #if 0
2892 case OP_R8CONST:
2893 case OP_R4CONST:
2894 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2895 temp->inst_c0 = (guint32)ins->inst_p0;
2896 temp->dreg = mono_alloc_ireg (cfg);
2897 ins->inst_basereg = temp->dreg;
2898 ins->inst_offset = 0;
2899 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2900 last_ins = temp;
2901 /* make it handle the possibly big ins->inst_offset
2902 * later optimize to use lis + load_membase
2904 goto loop_start;
2905 #endif
2906 case OP_IBEQ:
2907 g_assert (ins_is_compare(last_ins));
2908 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->sreg1, last_ins->sreg2);
2909 NULLIFY_INS(last_ins);
2910 break;
2912 case OP_IBNE_UN:
2913 g_assert (ins_is_compare(last_ins));
2914 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->sreg1, last_ins->sreg2);
2915 NULLIFY_INS(last_ins);
2916 break;
2918 case OP_IBGE:
2919 g_assert (ins_is_compare(last_ins));
2920 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2921 last_ins->dreg = mono_alloc_ireg (cfg);
2922 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2923 break;
2925 case OP_IBGE_UN:
2926 g_assert (ins_is_compare(last_ins));
2927 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2928 last_ins->dreg = mono_alloc_ireg (cfg);
2929 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2930 break;
2932 case OP_IBLT:
2933 g_assert (ins_is_compare(last_ins));
2934 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2935 last_ins->dreg = mono_alloc_ireg (cfg);
2936 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2937 break;
2939 case OP_IBLT_UN:
2940 g_assert (ins_is_compare(last_ins));
2941 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2942 last_ins->dreg = mono_alloc_ireg (cfg);
2943 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2944 break;
2946 case OP_IBLE:
2947 g_assert (ins_is_compare(last_ins));
2948 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2949 last_ins->dreg = mono_alloc_ireg (cfg);
2950 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2951 break;
2953 case OP_IBLE_UN:
2954 g_assert (ins_is_compare(last_ins));
2955 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2956 last_ins->dreg = mono_alloc_ireg (cfg);
2957 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2958 break;
2960 case OP_IBGT:
2961 g_assert (ins_is_compare(last_ins));
2962 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2963 last_ins->dreg = mono_alloc_ireg (cfg);
2964 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2965 break;
2967 case OP_IBGT_UN:
2968 g_assert (ins_is_compare(last_ins));
2969 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2970 last_ins->dreg = mono_alloc_ireg (cfg);
2971 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2972 break;
2974 case OP_CEQ:
2975 case OP_ICEQ:
2976 g_assert (ins_is_compare(last_ins));
2977 last_ins->opcode = OP_IXOR;
2978 last_ins->dreg = mono_alloc_ireg(cfg);
2979 INS_REWRITE_IMM(ins, OP_MIPS_SLTIU, last_ins->dreg, 1);
2980 break;
2982 case OP_CLT:
2983 case OP_ICLT:
2984 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2985 NULLIFY_INS(last_ins);
2986 break;
2989 case OP_CLT_UN:
2990 case OP_ICLT_UN:
2991 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2992 NULLIFY_INS(last_ins);
2993 break;
2995 case OP_CGT:
2996 case OP_ICGT:
2997 g_assert (ins_is_compare(last_ins));
2998 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2999 MONO_DELETE_INS(bb, last_ins);
3000 break;
3002 case OP_CGT_UN:
3003 case OP_ICGT_UN:
3004 g_assert (ins_is_compare(last_ins));
3005 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
3006 MONO_DELETE_INS(bb, last_ins);
3007 break;
3009 case OP_COND_EXC_EQ:
3010 case OP_COND_EXC_IEQ:
3011 g_assert (ins_is_compare(last_ins));
3012 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, last_ins->sreg1, last_ins->sreg2);
3013 MONO_DELETE_INS(bb, last_ins);
3014 break;
3016 case OP_COND_EXC_GE:
3017 case OP_COND_EXC_IGE:
3018 g_assert (ins_is_compare(last_ins));
3019 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE, last_ins->sreg1, last_ins->sreg2);
3020 MONO_DELETE_INS(bb, last_ins);
3021 break;
3023 case OP_COND_EXC_GT:
3024 case OP_COND_EXC_IGT:
3025 g_assert (ins_is_compare(last_ins));
3026 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT, last_ins->sreg1, last_ins->sreg2);
3027 MONO_DELETE_INS(bb, last_ins);
3028 break;
3030 case OP_COND_EXC_LE:
3031 case OP_COND_EXC_ILE:
3032 g_assert (ins_is_compare(last_ins));
3033 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE, last_ins->sreg1, last_ins->sreg2);
3034 MONO_DELETE_INS(bb, last_ins);
3035 break;
3037 case OP_COND_EXC_LT:
3038 case OP_COND_EXC_ILT:
3039 g_assert (ins_is_compare(last_ins));
3040 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT, last_ins->sreg1, last_ins->sreg2);
3041 MONO_DELETE_INS(bb, last_ins);
3042 break;
3044 case OP_COND_EXC_NE_UN:
3045 case OP_COND_EXC_INE_UN:
3046 g_assert (ins_is_compare(last_ins));
3047 INS_REWRITE(ins, OP_MIPS_COND_EXC_NE_UN, last_ins->sreg1, last_ins->sreg2);
3048 MONO_DELETE_INS(bb, last_ins);
3049 break;
3051 case OP_COND_EXC_GE_UN:
3052 case OP_COND_EXC_IGE_UN:
3053 g_assert (ins_is_compare(last_ins));
3054 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE_UN, last_ins->sreg1, last_ins->sreg2);
3055 MONO_DELETE_INS(bb, last_ins);
3056 break;
3058 case OP_COND_EXC_GT_UN:
3059 case OP_COND_EXC_IGT_UN:
3060 g_assert (ins_is_compare(last_ins));
3061 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT_UN, last_ins->sreg1, last_ins->sreg2);
3062 MONO_DELETE_INS(bb, last_ins);
3063 break;
3065 case OP_COND_EXC_LE_UN:
3066 case OP_COND_EXC_ILE_UN:
3067 g_assert (ins_is_compare(last_ins));
3068 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE_UN, last_ins->sreg1, last_ins->sreg2);
3069 MONO_DELETE_INS(bb, last_ins);
3070 break;
3072 case OP_COND_EXC_LT_UN:
3073 case OP_COND_EXC_ILT_UN:
3074 g_assert (ins_is_compare(last_ins));
3075 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT_UN, last_ins->sreg1, last_ins->sreg2);
3076 MONO_DELETE_INS(bb, last_ins);
3077 break;
3079 case OP_COND_EXC_OV:
3080 case OP_COND_EXC_IOV: {
3081 int tmp1, tmp2, tmp3, tmp4, tmp5;
3082 MonoInst *pos = last_ins;
3084 /* Overflow happens if
3085 * neg + neg = pos or
3086 * pos + pos = neg
3088 * (bit31s of operands match) AND (bit31 of operand
3089 * != bit31 of result)
3090 * XOR of the high bit returns 0 if the signs match
3091 * XOR of that with the high bit of the result return 1
3092 * if overflow.
3094 g_assert (last_ins->opcode == OP_IADC);
3096 tmp1 = mono_alloc_ireg (cfg);
3097 tmp2 = mono_alloc_ireg (cfg);
3098 tmp3 = mono_alloc_ireg (cfg);
3099 tmp4 = mono_alloc_ireg (cfg);
3100 tmp5 = mono_alloc_ireg (cfg);
3102 /* tmp1 = 0 if the signs of the two inputs match, else 1 */
3103 INS (pos, OP_IXOR, tmp1, last_ins->sreg1, last_ins->sreg2);
3105 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
3106 INS (pos, OP_IXOR, tmp2, last_ins->dreg, last_ins->sreg2);
3107 INS (pos, OP_INOT, tmp3, tmp2, -1);
3109 /* OR(tmp1, tmp2) = 0 if both conditions are true */
3110 INS (pos, OP_IOR, tmp4, tmp3, tmp1);
3111 INS_IMM (pos, OP_SHR_IMM, tmp5, tmp4, 31);
3113 /* Now, if (tmp5 == 0) then overflow */
3114 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, tmp5, mips_zero);
3115 ins->dreg = -1;
3116 break;
3119 case OP_COND_EXC_NO:
3120 case OP_COND_EXC_INO:
3121 g_assert_not_reached ();
3122 break;
3124 case OP_COND_EXC_C:
3125 case OP_COND_EXC_IC:
3126 g_assert_not_reached ();
3127 break;
3129 case OP_COND_EXC_NC:
3130 case OP_COND_EXC_INC:
3131 g_assert_not_reached ();
3132 break;
3135 last_ins = ins;
3137 bb->last_ins = last_ins;
3138 bb->max_vreg = cfg->next_vreg;
3140 #if 1
3141 if (cfg->verbose_level > 2) {
3142 int idx = 0;
3144 g_print ("BASIC BLOCK %d (after lowering)\n", bb->block_num);
3145 MONO_BB_FOR_EACH_INS (bb, ins) {
3146 mono_print_ins_index (idx++, ins);
3150 #endif
3154 static guchar*
3155 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
3157 /* sreg is a float, dreg is an integer reg. mips_at is used as scratch */
3158 #if 1
3159 mips_truncwd (code, mips_ftemp, sreg);
3160 #else
3161 mips_cvtwd (code, mips_ftemp, sreg);
3162 #endif
3163 mips_mfc1 (code, dreg, mips_ftemp);
3164 if (!is_signed) {
3165 if (size == 1)
3166 mips_andi (code, dreg, dreg, 0xff);
3167 else if (size == 2) {
3168 mips_sll (code, dreg, dreg, 16);
3169 mips_srl (code, dreg, dreg, 16);
3171 } else {
3172 if (size == 1) {
3173 mips_sll (code, dreg, dreg, 24);
3174 mips_sra (code, dreg, dreg, 24);
3176 else if (size == 2) {
3177 mips_sll (code, dreg, dreg, 16);
3178 mips_sra (code, dreg, dreg, 16);
3181 return code;
3185 * emit_load_volatile_arguments:
3187 * Load volatile arguments from the stack to the original input registers.
3188 * Required before a tail call.
3190 static guint8 *
3191 emit_load_volatile_arguments(MonoCompile *cfg, guint8 *code)
3193 MonoMethod *method = cfg->method;
3194 MonoMethodSignature *sig;
3195 MonoInst *inst;
3196 CallInfo *cinfo;
3197 int i;
3199 sig = mono_method_signature (method);
3201 if (!cfg->arch.cinfo)
3202 cfg->arch.cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
3203 cinfo = cfg->arch.cinfo;
3205 if (cinfo->struct_ret) {
3206 ArgInfo *ainfo = &cinfo->ret;
3207 inst = cfg->vret_addr;
3208 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3211 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3212 ArgInfo *ainfo = cinfo->args + i;
3213 inst = cfg->args [i];
3214 if (inst->opcode == OP_REGVAR) {
3215 if (ainfo->storage == ArgInIReg)
3216 MIPS_MOVE (code, ainfo->reg, inst->dreg);
3217 else if (ainfo->storage == ArgInFReg)
3218 g_assert_not_reached();
3219 else if (ainfo->storage == ArgOnStack) {
3220 /* do nothing */
3221 } else
3222 g_assert_not_reached ();
3223 } else {
3224 if (ainfo->storage == ArgInIReg) {
3225 g_assert (mips_is_imm16 (inst->inst_offset));
3226 switch (ainfo->size) {
3227 case 1:
3228 mips_lb (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3229 break;
3230 case 2:
3231 mips_lh (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3232 break;
3233 case 0: /* XXX */
3234 case 4:
3235 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3236 break;
3237 case 8:
3238 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
3239 mips_lw (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
3240 break;
3241 default:
3242 g_assert_not_reached ();
3243 break;
3245 } else if (ainfo->storage == ArgOnStack) {
3246 /* do nothing */
3247 } else if (ainfo->storage == ArgInFReg) {
3248 g_assert (mips_is_imm16 (inst->inst_offset));
3249 if (ainfo->size == 8) {
3250 #if _MIPS_SIM == _ABIO32
3251 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
3252 mips_lwc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
3253 #elif _MIPS_SIM == _ABIN32
3254 mips_ldc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3255 #endif
3257 else if (ainfo->size == 4)
3258 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3259 else
3260 g_assert_not_reached ();
3261 } else if (ainfo->storage == ArgStructByVal) {
3262 int i;
3263 int doffset = inst->inst_offset;
3265 g_assert (mips_is_imm16 (inst->inst_offset));
3266 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
3267 for (i = 0; i < ainfo->size; ++i) {
3268 mips_lw (code, ainfo->reg + i, inst->inst_basereg, doffset);
3269 doffset += SIZEOF_REGISTER;
3271 } else if (ainfo->storage == ArgStructByAddr) {
3272 g_assert (mips_is_imm16 (inst->inst_offset));
3273 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3274 } else
3275 g_assert_not_reached ();
3279 return code;
3282 static guint8*
3283 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
3285 int size = cfg->param_area;
3287 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3288 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3290 if (!size)
3291 return code;
3292 #if 0
3293 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3294 if (ppc_is_imm16 (-size)) {
3295 ppc_stwu (code, ppc_r0, -size, ppc_sp);
3296 } else {
3297 ppc_load (code, ppc_r11, -size);
3298 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
3300 #endif
3301 return code;
3304 static guint8*
3305 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
3307 int size = cfg->param_area;
3309 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3310 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3312 if (!size)
3313 return code;
3314 #if 0
3315 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3316 if (ppc_is_imm16 (size)) {
3317 ppc_stwu (code, ppc_r0, size, ppc_sp);
3318 } else {
3319 ppc_load (code, ppc_r11, size);
3320 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
3322 #endif
3323 return code;
3326 void
3327 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3329 MonoInst *ins;
3330 MonoCallInst *call;
3331 guint offset;
3332 guint8 *code = cfg->native_code + cfg->code_len;
3333 MonoInst *last_ins = NULL;
3334 guint last_offset = 0;
3335 int max_len, cpos;
3336 int ins_cnt = 0;
3338 /* we don't align basic blocks of loops on mips */
3340 if (cfg->verbose_level > 2)
3341 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3343 cpos = bb->max_offset;
3345 #if 0
3346 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
3347 MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
3348 g_assert (!mono_compile_aot);
3349 cpos += 20;
3350 if (bb->cil_code)
3351 cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
3352 /* this is not thread save, but good enough */
3353 /* fixme: howto handle overflows? */
3354 mips_load_const (code, mips_at, &cov->data [bb->dfn].count);
3355 mips_lw (code, mips_temp, mips_at, 0);
3356 mips_addiu (code, mips_temp, mips_temp, 1);
3357 mips_sw (code, mips_temp, mips_at, 0);
3359 #endif
3360 MONO_BB_FOR_EACH_INS (bb, ins) {
3361 offset = code - cfg->native_code;
3363 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3365 if (offset > (cfg->code_size - max_len - 16)) {
3366 cfg->code_size *= 2;
3367 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3368 code = cfg->native_code + offset;
3370 mono_debug_record_line_number (cfg, ins, offset);
3371 if (cfg->verbose_level > 2) {
3372 g_print (" @ 0x%x\t", offset);
3373 mono_print_ins_index (ins_cnt++, ins);
3375 /* Check for virtual regs that snuck by */
3376 g_assert ((ins->dreg >= -1) && (ins->dreg < 32));
3378 switch (ins->opcode) {
3379 case OP_RELAXED_NOP:
3380 case OP_NOP:
3381 case OP_DUMMY_USE:
3382 case OP_DUMMY_STORE:
3383 case OP_NOT_REACHED:
3384 case OP_NOT_NULL:
3385 break;
3386 case OP_SEQ_POINT: {
3387 if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
3388 guint32 addr = (guint32)ss_trigger_page;
3390 mips_load_const (code, mips_t9, addr);
3391 mips_lw (code, mips_t9, mips_t9, 0);
3394 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3397 * A placeholder for a possible breakpoint inserted by
3398 * mono_arch_set_breakpoint ().
3400 /* mips_load_const () + mips_lw */
3401 mips_nop (code);
3402 mips_nop (code);
3403 mips_nop (code);
3404 break;
3406 case OP_TLS_GET:
3407 g_assert_not_reached();
3408 #if 0
3409 emit_tls_access (code, ins->dreg, ins->inst_offset);
3410 #endif
3411 break;
3412 case OP_BIGMUL:
3413 mips_mult (code, ins->sreg1, ins->sreg2);
3414 mips_mflo (code, ins->dreg);
3415 mips_mfhi (code, ins->dreg+1);
3416 break;
3417 case OP_BIGMUL_UN:
3418 mips_multu (code, ins->sreg1, ins->sreg2);
3419 mips_mflo (code, ins->dreg);
3420 mips_mfhi (code, ins->dreg+1);
3421 break;
3422 case OP_MEMORY_BARRIER:
3423 #if 0
3424 ppc_sync (code);
3425 #endif
3426 break;
3427 case OP_STOREI1_MEMBASE_IMM:
3428 mips_load_const (code, mips_temp, ins->inst_imm);
3429 if (mips_is_imm16 (ins->inst_offset)) {
3430 mips_sb (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3431 } else {
3432 mips_load_const (code, mips_at, ins->inst_offset);
3433 mips_sb (code, mips_temp, mips_at, ins->inst_destbasereg);
3435 break;
3436 case OP_STOREI2_MEMBASE_IMM:
3437 mips_load_const (code, mips_temp, ins->inst_imm);
3438 if (mips_is_imm16 (ins->inst_offset)) {
3439 mips_sh (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3440 } else {
3441 mips_load_const (code, mips_at, ins->inst_offset);
3442 mips_sh (code, mips_temp, mips_at, ins->inst_destbasereg);
3444 break;
3445 case OP_STOREI8_MEMBASE_IMM:
3446 mips_load_const (code, mips_temp, ins->inst_imm);
3447 if (mips_is_imm16 (ins->inst_offset)) {
3448 mips_sd (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3449 } else {
3450 mips_load_const (code, mips_at, ins->inst_offset);
3451 mips_sd (code, mips_temp, mips_at, ins->inst_destbasereg);
3453 break;
3454 case OP_STORE_MEMBASE_IMM:
3455 case OP_STOREI4_MEMBASE_IMM:
3456 mips_load_const (code, mips_temp, ins->inst_imm);
3457 if (mips_is_imm16 (ins->inst_offset)) {
3458 mips_sw (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3459 } else {
3460 mips_load_const (code, mips_at, ins->inst_offset);
3461 mips_sw (code, mips_temp, mips_at, ins->inst_destbasereg);
3463 break;
3464 case OP_STOREI1_MEMBASE_REG:
3465 if (mips_is_imm16 (ins->inst_offset)) {
3466 mips_sb (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3467 } else {
3468 mips_load_const (code, mips_at, ins->inst_offset);
3469 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3470 mips_sb (code, ins->sreg1, mips_at, 0);
3472 break;
3473 case OP_STOREI2_MEMBASE_REG:
3474 if (mips_is_imm16 (ins->inst_offset)) {
3475 mips_sh (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3476 } else {
3477 mips_load_const (code, mips_at, ins->inst_offset);
3478 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3479 mips_sh (code, ins->sreg1, mips_at, 0);
3481 break;
3482 case OP_STORE_MEMBASE_REG:
3483 case OP_STOREI4_MEMBASE_REG:
3484 if (mips_is_imm16 (ins->inst_offset)) {
3485 mips_sw (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3486 } else {
3487 mips_load_const (code, mips_at, ins->inst_offset);
3488 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3489 mips_sw (code, ins->sreg1, mips_at, 0);
3491 break;
3492 case OP_STOREI8_MEMBASE_REG:
3493 if (mips_is_imm16 (ins->inst_offset)) {
3494 mips_sd (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3495 } else {
3496 mips_load_const (code, mips_at, ins->inst_offset);
3497 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3498 mips_sd (code, ins->sreg1, mips_at, 0);
3500 break;
3501 case OP_LOADU4_MEM:
3502 g_assert_not_reached ();
3503 //x86_mov_reg_imm (code, ins->dreg, ins->inst_p0);
3504 //x86_mov_reg_membase (code, ins->dreg, ins->dreg, 0, 4);
3505 break;
3506 case OP_LOADI8_MEMBASE:
3507 if (mips_is_imm16 (ins->inst_offset)) {
3508 mips_ld (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3509 } else {
3510 mips_load_const (code, mips_at, ins->inst_offset);
3511 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3512 mips_ld (code, ins->dreg, mips_at, 0);
3514 break;
3515 case OP_LOAD_MEMBASE:
3516 case OP_LOADI4_MEMBASE:
3517 case OP_LOADU4_MEMBASE:
3518 g_assert (ins->dreg != -1);
3519 if (mips_is_imm16 (ins->inst_offset)) {
3520 mips_lw (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3521 } else {
3522 mips_load_const (code, mips_at, ins->inst_offset);
3523 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3524 mips_lw (code, ins->dreg, mips_at, 0);
3526 break;
3527 case OP_LOADI1_MEMBASE:
3528 if (mips_is_imm16 (ins->inst_offset)) {
3529 mips_lb (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3530 } else {
3531 mips_load_const (code, mips_at, ins->inst_offset);
3532 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3533 mips_lb (code, ins->dreg, mips_at, 0);
3535 break;
3536 case OP_LOADU1_MEMBASE:
3537 if (mips_is_imm16 (ins->inst_offset)) {
3538 mips_lbu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3539 } else {
3540 mips_load_const (code, mips_at, ins->inst_offset);
3541 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3542 mips_lbu (code, ins->dreg, mips_at, 0);
3544 break;
3545 case OP_LOADI2_MEMBASE:
3546 if (mips_is_imm16 (ins->inst_offset)) {
3547 mips_lh (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3548 } else {
3549 mips_load_const (code, mips_at, ins->inst_offset);
3550 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3551 mips_lh (code, ins->dreg, mips_at, 0);
3553 break;
3554 case OP_LOADU2_MEMBASE:
3555 if (mips_is_imm16 (ins->inst_offset)) {
3556 mips_lhu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3557 } else {
3558 mips_load_const (code, mips_at, ins->inst_offset);
3559 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3560 mips_lhu (code, ins->dreg, mips_at, 0);
3562 break;
3563 case OP_ICONV_TO_I1:
3564 mips_sll (code, mips_at, ins->sreg1, 24);
3565 mips_sra (code, ins->dreg, mips_at, 24);
3566 break;
3567 case OP_ICONV_TO_I2:
3568 mips_sll (code, mips_at, ins->sreg1, 16);
3569 mips_sra (code, ins->dreg, mips_at, 16);
3570 break;
3571 case OP_ICONV_TO_U1:
3572 mips_andi (code, ins->dreg, ins->sreg1, 0xff);
3573 break;
3574 case OP_ICONV_TO_U2:
3575 mips_sll (code, mips_at, ins->sreg1, 16);
3576 mips_srl (code, ins->dreg, mips_at, 16);
3577 break;
3578 case OP_MIPS_SLT:
3579 mips_slt (code, ins->dreg, ins->sreg1, ins->sreg2);
3580 break;
3581 case OP_MIPS_SLTI:
3582 g_assert (mips_is_imm16 (ins->inst_imm));
3583 mips_slti (code, ins->dreg, ins->sreg1, ins->inst_imm);
3584 break;
3585 case OP_MIPS_SLTU:
3586 mips_sltu (code, ins->dreg, ins->sreg1, ins->sreg2);
3587 break;
3588 case OP_MIPS_SLTIU:
3589 g_assert (mips_is_imm16 (ins->inst_imm));
3590 mips_sltiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3591 break;
3592 case OP_BREAK:
3594 * gdb does not like encountering the hw breakpoint ins in the debugged code.
3595 * So instead of emitting a trap, we emit a call a C function and place a
3596 * breakpoint there.
3598 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3599 (gpointer)"mono_break");
3600 mips_load (code, mips_t9, 0x1f1f1f1f);
3601 mips_jalr (code, mips_t9, mips_ra);
3602 mips_nop (code);
3603 break;
3604 case OP_IADD:
3605 mips_addu (code, ins->dreg, ins->sreg1, ins->sreg2);
3606 break;
3607 case OP_LADD:
3608 mips_daddu (code, ins->dreg, ins->sreg1, ins->sreg2);
3609 break;
3611 case OP_ADD_IMM:
3612 case OP_IADD_IMM:
3613 g_assert (mips_is_imm16 (ins->inst_imm));
3614 mips_addiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3615 break;
3616 case OP_LADD_IMM:
3617 g_assert (mips_is_imm16 (ins->inst_imm));
3618 mips_daddiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3619 break;
3621 case OP_ISUB:
3622 mips_subu (code, ins->dreg, ins->sreg1, ins->sreg2);
3623 break;
3624 case OP_LSUB:
3625 mips_dsubu (code, ins->dreg, ins->sreg1, ins->sreg2);
3626 break;
3628 case OP_ISUB_IMM:
3629 case OP_SUB_IMM:
3630 // we add the negated value
3631 g_assert (mips_is_imm16 (-ins->inst_imm));
3632 mips_addiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3633 break;
3635 case OP_LSUB_IMM:
3636 // we add the negated value
3637 g_assert (mips_is_imm16 (-ins->inst_imm));
3638 mips_daddiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3639 break;
3641 case OP_IAND:
3642 case OP_LAND:
3643 mips_and (code, ins->dreg, ins->sreg1, ins->sreg2);
3644 break;
3646 case OP_AND_IMM:
3647 case OP_IAND_IMM:
3648 case OP_LAND_IMM:
3649 g_assert (!(ins->inst_imm & 0xffff0000));
3650 mips_andi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3651 break;
3653 case OP_IDIV:
3654 case OP_IREM: {
3655 guint32 *divisor_is_m1;
3656 guint32 *dividend_is_minvalue;
3657 guint32 *divisor_is_zero;
3659 mips_load_const (code, mips_at, -1);
3660 divisor_is_m1 = (guint32 *)(void *)code;
3661 mips_bne (code, ins->sreg2, mips_at, 0);
3662 mips_lui (code, mips_at, mips_zero, 0x8000);
3663 dividend_is_minvalue = (guint32 *)(void *)code;
3664 mips_bne (code, ins->sreg1, mips_at, 0);
3665 mips_nop (code);
3667 /* Divide Int32.MinValue by -1 -- throw exception */
3668 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3670 mips_patch (divisor_is_m1, (guint32)code);
3671 mips_patch (dividend_is_minvalue, (guint32)code);
3673 /* Put divide in branch delay slot (NOT YET) */
3674 divisor_is_zero = (guint32 *)(void *)code;
3675 mips_bne (code, ins->sreg2, mips_zero, 0);
3676 mips_nop (code);
3678 /* Divide by zero -- throw exception */
3679 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3681 mips_patch (divisor_is_zero, (guint32)code);
3682 mips_div (code, ins->sreg1, ins->sreg2);
3683 if (ins->opcode == OP_IDIV)
3684 mips_mflo (code, ins->dreg);
3685 else
3686 mips_mfhi (code, ins->dreg);
3687 break;
3689 case OP_IDIV_UN:
3690 case OP_IREM_UN: {
3691 guint32 *divisor_is_zero = (guint32 *)(void *)code;
3693 /* Put divide in branch delay slot (NOT YET) */
3694 mips_bne (code, ins->sreg2, mips_zero, 0);
3695 mips_nop (code);
3697 /* Divide by zero -- throw exception */
3698 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3700 mips_patch (divisor_is_zero, (guint32)code);
3701 mips_divu (code, ins->sreg1, ins->sreg2);
3702 if (ins->opcode == OP_IDIV_UN)
3703 mips_mflo (code, ins->dreg);
3704 else
3705 mips_mfhi (code, ins->dreg);
3706 break;
3708 case OP_DIV_IMM:
3709 g_assert_not_reached ();
3710 #if 0
3711 ppc_load (code, ppc_r11, ins->inst_imm);
3712 ppc_divwod (code, ins->dreg, ins->sreg1, ppc_r11);
3713 ppc_mfspr (code, ppc_r0, ppc_xer);
3714 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3715 /* FIXME: use OverflowException for 0x80000000/-1 */
3716 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3717 #endif
3718 g_assert_not_reached();
3719 break;
3720 case OP_REM_IMM:
3721 g_assert_not_reached ();
3722 case OP_IOR:
3723 mips_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3724 break;
3725 case OP_OR_IMM:
3726 case OP_IOR_IMM:
3727 g_assert (!(ins->inst_imm & 0xffff0000));
3728 mips_ori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3729 break;
3730 case OP_IXOR:
3731 mips_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3732 break;
3733 case OP_XOR_IMM:
3734 case OP_IXOR_IMM:
3735 /* unsigned 16-bit immediate */
3736 g_assert (!(ins->inst_imm & 0xffff0000));
3737 mips_xori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3738 break;
3739 case OP_ISHL:
3740 mips_sllv (code, ins->dreg, ins->sreg1, ins->sreg2);
3741 break;
3742 case OP_SHL_IMM:
3743 case OP_ISHL_IMM:
3744 mips_sll (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3745 break;
3746 case OP_ISHR:
3747 mips_srav (code, ins->dreg, ins->sreg1, ins->sreg2);
3748 break;
3749 case OP_LSHR:
3750 mips_dsrav (code, ins->dreg, ins->sreg1, ins->sreg2);
3751 break;
3752 case OP_SHR_IMM:
3753 case OP_ISHR_IMM:
3754 mips_sra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3755 break;
3756 case OP_LSHR_IMM:
3757 mips_dsra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3758 break;
3759 case OP_SHR_UN_IMM:
3760 case OP_ISHR_UN_IMM:
3761 mips_srl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3762 break;
3763 case OP_LSHR_UN_IMM:
3764 mips_dsrl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3765 break;
3766 case OP_ISHR_UN:
3767 mips_srlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3768 break;
3769 case OP_LSHR_UN:
3770 mips_dsrlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3771 break;
3772 case OP_INOT:
3773 case OP_LNOT:
3774 mips_nor (code, ins->dreg, mips_zero, ins->sreg1);
3775 break;
3776 case OP_INEG:
3777 mips_subu (code, ins->dreg, mips_zero, ins->sreg1);
3778 break;
3779 case OP_LNEG:
3780 mips_dsubu (code, ins->dreg, mips_zero, ins->sreg1);
3781 break;
3782 case OP_IMUL:
3783 #if USE_MUL
3784 mips_mul (code, ins->dreg, ins->sreg1, ins->sreg2);
3785 #else
3786 mips_mult (code, ins->sreg1, ins->sreg2);
3787 mips_mflo (code, ins->dreg);
3788 mips_nop (code);
3789 mips_nop (code);
3790 #endif
3791 break;
3792 #if SIZEOF_REGISTER == 8
3793 case OP_LMUL:
3794 mips_dmult (code, ins->sreg1, ins->sreg2);
3795 mips_mflo (code, ins->dreg);
3796 break;
3797 #endif
3798 case OP_IMUL_OVF: {
3799 guint32 *patch;
3800 mips_mult (code, ins->sreg1, ins->sreg2);
3801 mips_mflo (code, ins->dreg);
3802 mips_mfhi (code, mips_at);
3803 mips_nop (code);
3804 mips_nop (code);
3805 mips_sra (code, mips_temp, ins->dreg, 31);
3806 patch = (guint32 *)(void *)code;
3807 mips_beq (code, mips_temp, mips_at, 0);
3808 mips_nop (code);
3809 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3810 mips_patch (patch, (guint32)code);
3811 break;
3813 case OP_IMUL_OVF_UN: {
3814 guint32 *patch;
3815 mips_mult (code, ins->sreg1, ins->sreg2);
3816 mips_mflo (code, ins->dreg);
3817 mips_mfhi (code, mips_at);
3818 mips_nop (code);
3819 mips_nop (code);
3820 patch = (guint32 *)(void *)code;
3821 mips_beq (code, mips_at, mips_zero, 0);
3822 mips_nop (code);
3823 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3824 mips_patch (patch, (guint32)code);
3825 break;
3827 case OP_ICONST:
3828 mips_load_const (code, ins->dreg, ins->inst_c0);
3829 break;
3830 #if SIZEOF_REGISTER == 8
3831 case OP_I8CONST:
3832 mips_load_const (code, ins->dreg, ins->inst_c0);
3833 break;
3834 #endif
3835 case OP_AOTCONST:
3836 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3837 mips_load (code, ins->dreg, 0);
3838 break;
3840 case OP_MIPS_MTC1S:
3841 mips_mtc1 (code, ins->dreg, ins->sreg1);
3842 break;
3843 case OP_MIPS_MTC1S_2:
3844 mips_mtc1 (code, ins->dreg, ins->sreg1);
3845 mips_mtc1 (code, ins->dreg+1, ins->sreg2);
3846 break;
3847 case OP_MIPS_MFC1S:
3848 mips_mfc1 (code, ins->dreg, ins->sreg1);
3849 break;
3850 case OP_MIPS_MTC1D:
3851 mips_dmtc1 (code, ins->dreg, ins->sreg1);
3852 break;
3853 case OP_MIPS_MFC1D:
3854 #if 0
3855 mips_dmfc1 (code, ins->dreg, ins->sreg1);
3856 #else
3857 mips_mfc1 (code, ins->dreg, ins->sreg1 + ls_word_idx);
3858 mips_mfc1 (code, ins->dreg+1, ins->sreg1 + ms_word_idx);
3859 #endif
3860 break;
3862 case OP_ICONV_TO_I4:
3863 case OP_ICONV_TO_U4:
3864 case OP_MOVE:
3865 if (ins->dreg != ins->sreg1)
3866 MIPS_MOVE (code, ins->dreg, ins->sreg1);
3867 break;
3868 #if SIZEOF_REGISTER == 8
3869 case OP_ZEXT_I4:
3870 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3871 mips_dsrl (code, ins->dreg, ins->dreg, 32);
3872 break;
3873 case OP_SEXT_I4:
3874 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3875 mips_dsra (code, ins->dreg, ins->dreg, 32);
3876 break;
3877 #endif
3878 case OP_SETLRET: {
3879 int lsreg = mips_v0 + ls_word_idx;
3880 int msreg = mips_v0 + ms_word_idx;
3882 /* Get sreg1 into lsreg, sreg2 into msreg */
3884 if (ins->sreg1 == msreg) {
3885 if (ins->sreg1 != mips_at)
3886 MIPS_MOVE (code, mips_at, ins->sreg1);
3887 if (ins->sreg2 != msreg)
3888 MIPS_MOVE (code, msreg, ins->sreg2);
3889 MIPS_MOVE (code, lsreg, mips_at);
3891 else {
3892 if (ins->sreg2 != msreg)
3893 MIPS_MOVE (code, msreg, ins->sreg2);
3894 if (ins->sreg1 != lsreg)
3895 MIPS_MOVE (code, lsreg, ins->sreg1);
3897 break;
3899 case OP_FMOVE:
3900 if (ins->dreg != ins->sreg1) {
3901 mips_fmovd (code, ins->dreg, ins->sreg1);
3903 break;
3904 case OP_MIPS_CVTSD:
3905 /* Convert from double to float and leave it there */
3906 mips_cvtsd (code, ins->dreg, ins->sreg1);
3907 break;
3908 case OP_FCONV_TO_R4:
3909 #if 0
3910 mips_cvtsd (code, ins->dreg, ins->sreg1);
3911 #else
3912 /* Just a move, no precision change */
3913 if (ins->dreg != ins->sreg1) {
3914 mips_fmovd (code, ins->dreg, ins->sreg1);
3916 #endif
3917 break;
3918 case OP_JMP:
3919 code = emit_load_volatile_arguments(cfg, code);
3922 * Pop our stack, then jump to specified method (tail-call)
3923 * Keep in sync with mono_arch_emit_epilog
3925 code = mono_arch_emit_epilog_sub (cfg, code);
3927 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code,
3928 MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3929 mips_load (code, mips_t9, 0);
3930 mips_jr (code, mips_t9);
3931 mips_nop (code);
3932 break;
3933 case OP_CHECK_THIS:
3934 /* ensure ins->sreg1 is not NULL */
3935 mips_lw (code, mips_zero, ins->sreg1, 0);
3936 break;
3937 case OP_ARGLIST: {
3938 g_assert (mips_is_imm16 (cfg->sig_cookie));
3939 mips_lw (code, mips_at, cfg->frame_reg, cfg->sig_cookie);
3940 mips_sw (code, mips_at, ins->sreg1, 0);
3941 break;
3943 case OP_FCALL:
3944 case OP_LCALL:
3945 case OP_VCALL:
3946 case OP_VCALL2:
3947 case OP_VOIDCALL:
3948 case OP_CALL:
3949 case OP_FCALL_REG:
3950 case OP_LCALL_REG:
3951 case OP_VCALL_REG:
3952 case OP_VCALL2_REG:
3953 case OP_VOIDCALL_REG:
3954 case OP_CALL_REG:
3955 case OP_FCALL_MEMBASE:
3956 case OP_LCALL_MEMBASE:
3957 case OP_VCALL_MEMBASE:
3958 case OP_VCALL2_MEMBASE:
3959 case OP_VOIDCALL_MEMBASE:
3960 case OP_CALL_MEMBASE:
3961 call = (MonoCallInst*)ins;
3962 switch (ins->opcode) {
3963 case OP_FCALL:
3964 case OP_LCALL:
3965 case OP_VCALL:
3966 case OP_VCALL2:
3967 case OP_VOIDCALL:
3968 case OP_CALL:
3969 if (ins->flags & MONO_INST_HAS_METHOD) {
3970 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3971 mips_load (code, mips_t9, call->method);
3973 else {
3974 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3975 mips_load (code, mips_t9, call->fptr);
3977 mips_jalr (code, mips_t9, mips_ra);
3978 mips_nop (code);
3979 break;
3980 case OP_FCALL_REG:
3981 case OP_LCALL_REG:
3982 case OP_VCALL_REG:
3983 case OP_VCALL2_REG:
3984 case OP_VOIDCALL_REG:
3985 case OP_CALL_REG:
3986 MIPS_MOVE (code, mips_t9, ins->sreg1);
3987 mips_jalr (code, mips_t9, mips_ra);
3988 mips_nop (code);
3989 break;
3990 case OP_FCALL_MEMBASE:
3991 case OP_LCALL_MEMBASE:
3992 case OP_VCALL_MEMBASE:
3993 case OP_VCALL2_MEMBASE:
3994 case OP_VOIDCALL_MEMBASE:
3995 case OP_CALL_MEMBASE:
3996 mips_lw (code, mips_t9, ins->sreg1, ins->inst_offset);
3997 mips_jalr (code, mips_t9, mips_ra);
3998 mips_nop (code);
3999 break;
4001 #if PROMOTE_R4_TO_R8
4002 /* returned an FP R4 (single), promote to R8 (double) in place */
4003 switch (ins->opcode) {
4004 case OP_FCALL:
4005 case OP_FCALL_REG:
4006 case OP_FCALL_MEMBASE:
4007 if (call->signature->ret->type == MONO_TYPE_R4)
4008 mips_cvtds (code, mips_f0, mips_f0);
4009 break;
4010 default:
4011 break;
4013 #endif
4014 break;
4015 case OP_LOCALLOC: {
4016 int area_offset = cfg->param_area;
4018 /* Round up ins->sreg1, mips_at ends up holding size */
4019 mips_addiu (code, mips_at, ins->sreg1, 31);
4020 mips_addiu (code, mips_temp, mips_zero, ~31);
4021 mips_and (code, mips_at, mips_at, mips_temp);
4023 mips_subu (code, mips_sp, mips_sp, mips_at);
4024 g_assert (mips_is_imm16 (area_offset));
4025 mips_addiu (code, ins->dreg, mips_sp, area_offset);
4027 if (ins->flags & MONO_INST_INIT) {
4028 guint32 *buf;
4030 buf = (guint32*)(void*)code;
4031 mips_beq (code, mips_at, mips_zero, 0);
4032 mips_nop (code);
4034 mips_move (code, mips_temp, ins->dreg);
4035 mips_sb (code, mips_zero, mips_temp, 0);
4036 mips_addiu (code, mips_at, mips_at, -1);
4037 mips_bne (code, mips_at, mips_zero, -3);
4038 mips_addiu (code, mips_temp, mips_temp, 1);
4040 mips_patch (buf, (guint32)code);
4042 break;
4044 case OP_THROW: {
4045 gpointer addr = mono_arch_get_throw_exception(NULL, FALSE);
4046 mips_move (code, mips_a0, ins->sreg1);
4047 mips_call (code, mips_t9, addr);
4048 mips_break (code, 0xfc);
4049 break;
4051 case OP_RETHROW: {
4052 gpointer addr = mono_arch_get_rethrow_exception(NULL, FALSE);
4053 mips_move (code, mips_a0, ins->sreg1);
4054 mips_call (code, mips_t9, addr);
4055 mips_break (code, 0xfb);
4056 break;
4058 case OP_START_HANDLER: {
4060 * The START_HANDLER instruction marks the beginning of
4061 * a handler block. It is called using a call
4062 * instruction, so mips_ra contains the return address.
4063 * Since the handler executes in the same stack frame
4064 * as the method itself, we can't use save/restore to
4065 * save the return address. Instead, we save it into
4066 * a dedicated variable.
4068 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4069 g_assert (spvar->inst_basereg != mips_sp);
4070 code = emit_reserve_param_area (cfg, code);
4072 if (mips_is_imm16 (spvar->inst_offset)) {
4073 mips_sw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
4074 } else {
4075 mips_load_const (code, mips_at, spvar->inst_offset);
4076 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
4077 mips_sw (code, mips_ra, mips_at, 0);
4079 break;
4081 case OP_ENDFILTER: {
4082 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4083 g_assert (spvar->inst_basereg != mips_sp);
4084 code = emit_unreserve_param_area (cfg, code);
4086 if (ins->sreg1 != mips_v0)
4087 MIPS_MOVE (code, mips_v0, ins->sreg1);
4088 if (mips_is_imm16 (spvar->inst_offset)) {
4089 mips_lw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
4090 } else {
4091 mips_load_const (code, mips_at, spvar->inst_offset);
4092 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
4093 mips_lw (code, mips_ra, mips_at, 0);
4095 mips_jr (code, mips_ra);
4096 mips_nop (code);
4097 break;
4099 case OP_ENDFINALLY: {
4100 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4101 g_assert (spvar->inst_basereg != mips_sp);
4102 code = emit_unreserve_param_area (cfg, code);
4103 mips_lw (code, mips_t9, spvar->inst_basereg, spvar->inst_offset);
4104 mips_jalr (code, mips_t9, mips_ra);
4105 mips_nop (code);
4106 break;
4108 case OP_CALL_HANDLER:
4109 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4110 mips_lui (code, mips_t9, mips_zero, 0);
4111 mips_addiu (code, mips_t9, mips_t9, 0);
4112 mips_jalr (code, mips_t9, mips_ra);
4113 mips_nop (code);
4114 /*FIXME should it be before the NOP or not? Does MIPS has a delay slot like sparc?*/
4115 mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
4116 break;
4117 case OP_LABEL:
4118 ins->inst_c0 = code - cfg->native_code;
4119 break;
4120 case OP_BR:
4121 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4122 if (cfg->arch.long_branch) {
4123 mips_lui (code, mips_at, mips_zero, 0);
4124 mips_addiu (code, mips_at, mips_at, 0);
4125 mips_jr (code, mips_at);
4126 mips_nop (code);
4128 else {
4129 mips_beq (code, mips_zero, mips_zero, 0);
4130 mips_nop (code);
4132 break;
4133 case OP_BR_REG:
4134 mips_jr (code, ins->sreg1);
4135 mips_nop (code);
4136 break;
4137 case OP_SWITCH: {
4138 int i;
4140 max_len += 4 * GPOINTER_TO_INT (ins->klass);
4141 if (offset > (cfg->code_size - max_len - 16)) {
4142 cfg->code_size += max_len;
4143 cfg->code_size *= 2;
4144 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4145 code = cfg->native_code + offset;
4147 g_assert (ins->sreg1 != -1);
4148 mips_sll (code, mips_at, ins->sreg1, 2);
4149 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS))
4150 MIPS_MOVE (code, mips_t8, mips_ra);
4151 mips_bgezal (code, mips_zero, 1); /* bal */
4152 mips_nop (code);
4153 mips_addu (code, mips_t9, mips_ra, mips_at);
4154 /* Table is 16 or 20 bytes from target of bal above */
4155 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS)) {
4156 MIPS_MOVE (code, mips_ra, mips_t8);
4157 mips_lw (code, mips_t9, mips_t9, 20);
4159 else
4160 mips_lw (code, mips_t9, mips_t9, 16);
4161 mips_jalr (code, mips_t9, mips_t8);
4162 mips_nop (code);
4163 for (i = 0; i < GPOINTER_TO_INT (ins->klass); ++i)
4164 mips_emit32 (code, 0xfefefefe);
4165 break;
4167 case OP_CEQ:
4168 case OP_ICEQ:
4169 mips_addiu (code, ins->dreg, mips_zero, 1);
4170 mips_beq (code, mips_at, mips_zero, 2);
4171 mips_nop (code);
4172 MIPS_MOVE (code, ins->dreg, mips_zero);
4173 break;
4174 case OP_CLT:
4175 case OP_CLT_UN:
4176 case OP_ICLT:
4177 case OP_ICLT_UN:
4178 mips_addiu (code, ins->dreg, mips_zero, 1);
4179 mips_bltz (code, mips_at, 2);
4180 mips_nop (code);
4181 MIPS_MOVE (code, ins->dreg, mips_zero);
4182 break;
4183 case OP_CGT:
4184 case OP_CGT_UN:
4185 case OP_ICGT:
4186 case OP_ICGT_UN:
4187 mips_addiu (code, ins->dreg, mips_zero, 1);
4188 mips_bgtz (code, mips_at, 2);
4189 mips_nop (code);
4190 MIPS_MOVE (code, ins->dreg, mips_zero);
4191 break;
4193 case OP_MIPS_COND_EXC_EQ:
4194 case OP_MIPS_COND_EXC_GE:
4195 case OP_MIPS_COND_EXC_GT:
4196 case OP_MIPS_COND_EXC_LE:
4197 case OP_MIPS_COND_EXC_LT:
4198 case OP_MIPS_COND_EXC_NE_UN:
4199 case OP_MIPS_COND_EXC_GE_UN:
4200 case OP_MIPS_COND_EXC_GT_UN:
4201 case OP_MIPS_COND_EXC_LE_UN:
4202 case OP_MIPS_COND_EXC_LT_UN:
4204 case OP_MIPS_COND_EXC_OV:
4205 case OP_MIPS_COND_EXC_NO:
4206 case OP_MIPS_COND_EXC_C:
4207 case OP_MIPS_COND_EXC_NC:
4209 case OP_MIPS_COND_EXC_IEQ:
4210 case OP_MIPS_COND_EXC_IGE:
4211 case OP_MIPS_COND_EXC_IGT:
4212 case OP_MIPS_COND_EXC_ILE:
4213 case OP_MIPS_COND_EXC_ILT:
4214 case OP_MIPS_COND_EXC_INE_UN:
4215 case OP_MIPS_COND_EXC_IGE_UN:
4216 case OP_MIPS_COND_EXC_IGT_UN:
4217 case OP_MIPS_COND_EXC_ILE_UN:
4218 case OP_MIPS_COND_EXC_ILT_UN:
4220 case OP_MIPS_COND_EXC_IOV:
4221 case OP_MIPS_COND_EXC_INO:
4222 case OP_MIPS_COND_EXC_IC:
4223 case OP_MIPS_COND_EXC_INC: {
4224 guint32 *skip;
4225 guint32 *throw;
4227 /* If the condition is true, raise the exception */
4229 /* need to reverse test to skip around exception raising */
4231 /* For the moment, branch around a branch to avoid reversing
4232 the tests. */
4234 /* Remember, an unpatched branch to 0 branches to the delay slot */
4235 switch (ins->opcode) {
4236 case OP_MIPS_COND_EXC_EQ:
4237 throw = (guint32 *)(void *)code;
4238 mips_beq (code, ins->sreg1, ins->sreg2, 0);
4239 mips_nop (code);
4240 break;
4242 case OP_MIPS_COND_EXC_NE_UN:
4243 throw = (guint32 *)(void *)code;
4244 mips_bne (code, ins->sreg1, ins->sreg2, 0);
4245 mips_nop (code);
4246 break;
4248 case OP_MIPS_COND_EXC_LE_UN:
4249 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
4250 throw = (guint32 *)(void *)code;
4251 mips_beq (code, mips_at, mips_zero, 0);
4252 mips_nop (code);
4253 break;
4255 case OP_MIPS_COND_EXC_GT:
4256 mips_slt (code, mips_at, ins->sreg2, ins->sreg1);
4257 throw = (guint32 *)(void *)code;
4258 mips_bne (code, mips_at, mips_zero, 0);
4259 mips_nop (code);
4260 break;
4262 case OP_MIPS_COND_EXC_GT_UN:
4263 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
4264 throw = (guint32 *)(void *)code;
4265 mips_bne (code, mips_at, mips_zero, 0);
4266 mips_nop (code);
4267 break;
4269 case OP_MIPS_COND_EXC_LT:
4270 mips_slt (code, mips_at, ins->sreg1, ins->sreg2);
4271 throw = (guint32 *)(void *)code;
4272 mips_bne (code, mips_at, mips_zero, 0);
4273 mips_nop (code);
4274 break;
4276 case OP_MIPS_COND_EXC_LT_UN:
4277 mips_sltu (code, mips_at, ins->sreg1, ins->sreg2);
4278 throw = (guint32 *)(void *)code;
4279 mips_bne (code, mips_at, mips_zero, 0);
4280 mips_nop (code);
4281 break;
4283 default:
4284 /* Not yet implemented */
4285 g_warning ("NYI conditional exception %s\n", mono_inst_name (ins->opcode));
4286 g_assert_not_reached ();
4288 skip = (guint32 *)(void *)code;
4289 mips_beq (code, mips_zero, mips_zero, 0);
4290 mips_nop (code);
4291 mips_patch (throw, (guint32)code);
4292 code = mips_emit_exc_by_name (code, ins->inst_p1);
4293 mips_patch (skip, (guint32)code);
4294 cfg->bb_exit->max_offset += 24;
4295 break;
4297 case OP_MIPS_BEQ:
4298 case OP_MIPS_BNE:
4299 case OP_MIPS_BGEZ:
4300 case OP_MIPS_BGTZ:
4301 case OP_MIPS_BLEZ:
4302 case OP_MIPS_BLTZ:
4303 code = mips_emit_cond_branch (cfg, code, ins->opcode, ins);
4304 break;
4306 /* floating point opcodes */
4307 case OP_R8CONST:
4308 #if 0
4309 if (((guint32)ins->inst_p0) & (1 << 15))
4310 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4311 else
4312 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4313 mips_ldc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4314 #else
4315 mips_load_const (code, mips_at, ins->inst_p0);
4316 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4317 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4318 #endif
4319 break;
4320 case OP_R4CONST:
4321 if (((guint32)ins->inst_p0) & (1 << 15))
4322 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4323 else
4324 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4325 mips_lwc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4326 #if PROMOTE_R4_TO_R8
4327 mips_cvtds (code, ins->dreg, ins->dreg);
4328 #endif
4329 break;
4330 case OP_STORER8_MEMBASE_REG:
4331 if (mips_is_imm16 (ins->inst_offset)) {
4332 #if _MIPS_SIM == _ABIO32
4333 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset + ls_word_offset);
4334 mips_swc1 (code, ins->sreg1+1, ins->inst_destbasereg, ins->inst_offset + ms_word_offset);
4335 #elif _MIPS_SIM == _ABIN32
4336 mips_sdc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4337 #endif
4338 } else {
4339 mips_load_const (code, mips_at, ins->inst_offset);
4340 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
4341 mips_swc1 (code, ins->sreg1, mips_at, ls_word_offset);
4342 mips_swc1 (code, ins->sreg1+1, mips_at, ms_word_offset);
4344 break;
4345 case OP_LOADR8_MEMBASE:
4346 if (mips_is_imm16 (ins->inst_offset)) {
4347 #if _MIPS_SIM == _ABIO32
4348 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset + ls_word_offset);
4349 mips_lwc1 (code, ins->dreg+1, ins->inst_basereg, ins->inst_offset + ms_word_offset);
4350 #elif _MIPS_SIM == _ABIN32
4351 mips_ldc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4352 #endif
4353 } else {
4354 mips_load_const (code, mips_at, ins->inst_offset);
4355 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
4356 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4357 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4359 break;
4360 case OP_STORER4_MEMBASE_REG:
4361 g_assert (mips_is_imm16 (ins->inst_offset));
4362 #if PROMOTE_R4_TO_R8
4363 /* Need to convert ins->sreg1 to single-precision first */
4364 mips_cvtsd (code, mips_ftemp, ins->sreg1);
4365 mips_swc1 (code, mips_ftemp, ins->inst_destbasereg, ins->inst_offset);
4366 #else
4367 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4368 #endif
4369 break;
4370 case OP_MIPS_LWC1:
4371 g_assert (mips_is_imm16 (ins->inst_offset));
4372 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4373 break;
4374 case OP_LOADR4_MEMBASE:
4375 g_assert (mips_is_imm16 (ins->inst_offset));
4376 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4377 #if PROMOTE_R4_TO_R8
4378 /* Convert to double precision in place */
4379 mips_cvtds (code, ins->dreg, ins->dreg);
4380 #endif
4381 break;
4382 case OP_LOADR4_MEMINDEX:
4383 mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4384 mips_lwc1 (code, ins->dreg, mips_at, 0);
4385 break;
4386 case OP_LOADR8_MEMINDEX:
4387 mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4388 #if _MIPS_SIM == _ABIO32
4389 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4390 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4391 #elif _MIPS_SIM == _ABIN32
4392 mips_ldc1 (code, ins->dreg, mips_at, 0);
4393 #endif
4394 break;
4395 case OP_STORER4_MEMINDEX:
4396 mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4397 #if PROMOTE_R4_TO_R8
4398 /* Need to convert ins->sreg1 to single-precision first */
4399 mips_cvtsd (code, mips_ftemp, ins->sreg1);
4400 mips_swc1 (code, mips_ftemp, mips_at, 0);
4401 #else
4402 mips_swc1 (code, ins->sreg1, mips_at, 0);
4403 #endif
4404 break;
4405 case OP_STORER8_MEMINDEX:
4406 mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4407 #if _MIPS_SIM == _ABIO32
4408 mips_swc1 (code, ins->sreg1, mips_at, ls_word_offset);
4409 mips_swc1 (code, ins->sreg1+1, mips_at, ms_word_offset);
4410 #elif _MIPS_SIM == _ABIN32
4411 mips_sdc1 (code, ins->sreg1, mips_at, 0);
4412 #endif
4413 break;
4414 case OP_ICONV_TO_R_UN: {
4415 static const guint64 adjust_val = 0x41F0000000000000ULL;
4417 /* convert unsigned int to double */
4418 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4419 mips_bgez (code, ins->sreg1, 5);
4420 mips_cvtdw (code, ins->dreg, mips_ftemp);
4422 mips_load (code, mips_at, (guint32) &adjust_val);
4423 mips_ldc1 (code, mips_ftemp, mips_at, 0);
4424 mips_faddd (code, ins->dreg, ins->dreg, mips_ftemp);
4425 /* target is here */
4426 break;
4428 case OP_ICONV_TO_R4:
4429 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4430 mips_cvtsw (code, ins->dreg, mips_ftemp);
4431 mips_cvtds (code, ins->dreg, ins->dreg);
4432 break;
4433 case OP_ICONV_TO_R8:
4434 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4435 mips_cvtdw (code, ins->dreg, mips_ftemp);
4436 break;
4437 case OP_FCONV_TO_I1:
4438 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4439 break;
4440 case OP_FCONV_TO_U1:
4441 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4442 break;
4443 case OP_FCONV_TO_I2:
4444 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4445 break;
4446 case OP_FCONV_TO_U2:
4447 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4448 break;
4449 case OP_FCONV_TO_I4:
4450 case OP_FCONV_TO_I:
4451 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4452 break;
4453 case OP_FCONV_TO_U4:
4454 case OP_FCONV_TO_U:
4455 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4456 break;
4457 case OP_SQRT:
4458 mips_fsqrtd (code, ins->dreg, ins->sreg1);
4459 break;
4460 case OP_FADD:
4461 mips_faddd (code, ins->dreg, ins->sreg1, ins->sreg2);
4462 break;
4463 case OP_FSUB:
4464 mips_fsubd (code, ins->dreg, ins->sreg1, ins->sreg2);
4465 break;
4466 case OP_FMUL:
4467 mips_fmuld (code, ins->dreg, ins->sreg1, ins->sreg2);
4468 break;
4469 case OP_FDIV:
4470 mips_fdivd (code, ins->dreg, ins->sreg1, ins->sreg2);
4471 break;
4472 case OP_FNEG:
4473 mips_fnegd (code, ins->dreg, ins->sreg1);
4474 break;
4475 case OP_FCEQ:
4476 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
4477 mips_addiu (code, ins->dreg, mips_zero, 1);
4478 mips_fbtrue (code, 2);
4479 mips_nop (code);
4480 MIPS_MOVE (code, ins->dreg, mips_zero);
4481 break;
4482 case OP_FCLT:
4483 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
4484 mips_addiu (code, ins->dreg, mips_zero, 1);
4485 mips_fbtrue (code, 2);
4486 mips_nop (code);
4487 MIPS_MOVE (code, ins->dreg, mips_zero);
4488 break;
4489 case OP_FCLT_UN:
4490 /* Less than, or Unordered */
4491 mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
4492 mips_addiu (code, ins->dreg, mips_zero, 1);
4493 mips_fbtrue (code, 2);
4494 mips_nop (code);
4495 MIPS_MOVE (code, ins->dreg, mips_zero);
4496 break;
4497 case OP_FCGT:
4498 mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
4499 MIPS_MOVE (code, ins->dreg, mips_zero);
4500 mips_fbtrue (code, 2);
4501 mips_nop (code);
4502 mips_addiu (code, ins->dreg, mips_zero, 1);
4503 break;
4504 case OP_FCGT_UN:
4505 /* Greater than, or Unordered */
4506 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
4507 MIPS_MOVE (code, ins->dreg, mips_zero);
4508 mips_fbtrue (code, 2);
4509 mips_nop (code);
4510 mips_addiu (code, ins->dreg, mips_zero, 1);
4511 break;
4512 case OP_MIPS_FBEQ:
4513 case OP_MIPS_FBNE:
4514 case OP_MIPS_FBLT:
4515 case OP_MIPS_FBLT_UN:
4516 case OP_MIPS_FBGT:
4517 case OP_MIPS_FBGT_UN:
4518 case OP_MIPS_FBGE:
4519 case OP_MIPS_FBGE_UN:
4520 case OP_MIPS_FBLE:
4521 case OP_MIPS_FBLE_UN: {
4522 int cond = 0;
4523 gboolean is_true = TRUE, is_ordered = FALSE;
4524 guint32 *buf = NULL;
4526 switch (ins->opcode) {
4527 case OP_MIPS_FBEQ:
4528 cond = MIPS_FPU_EQ;
4529 is_true = TRUE;
4530 break;
4531 case OP_MIPS_FBNE:
4532 cond = MIPS_FPU_EQ;
4533 is_true = FALSE;
4534 break;
4535 case OP_MIPS_FBLT:
4536 cond = MIPS_FPU_LT;
4537 is_true = TRUE;
4538 is_ordered = TRUE;
4539 break;
4540 case OP_MIPS_FBLT_UN:
4541 cond = MIPS_FPU_ULT;
4542 is_true = TRUE;
4543 break;
4544 case OP_MIPS_FBGT:
4545 cond = MIPS_FPU_LE;
4546 is_true = FALSE;
4547 is_ordered = TRUE;
4548 break;
4549 case OP_MIPS_FBGT_UN:
4550 cond = MIPS_FPU_OLE;
4551 is_true = FALSE;
4552 break;
4553 case OP_MIPS_FBGE:
4554 cond = MIPS_FPU_LT;
4555 is_true = FALSE;
4556 is_ordered = TRUE;
4557 break;
4558 case OP_MIPS_FBGE_UN:
4559 cond = MIPS_FPU_OLT;
4560 is_true = FALSE;
4561 break;
4562 case OP_MIPS_FBLE:
4563 cond = MIPS_FPU_OLE;
4564 is_true = TRUE;
4565 is_ordered = TRUE;
4566 break;
4567 case OP_MIPS_FBLE_UN:
4568 cond = MIPS_FPU_ULE;
4569 is_true = TRUE;
4570 break;
4571 default:
4572 g_assert_not_reached ();
4575 if (is_ordered) {
4576 /* Skip the check if unordered */
4577 mips_fcmpd (code, MIPS_FPU_UN, ins->sreg1, ins->sreg2);
4578 mips_nop (code);
4579 buf = (guint32*)code;
4580 mips_fbtrue (code, 0);
4581 mips_nop (code);
4584 mips_fcmpd (code, cond, ins->sreg1, ins->sreg2);
4585 mips_nop (code);
4586 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4587 if (is_true)
4588 mips_fbtrue (code, 0);
4589 else
4590 mips_fbfalse (code, 0);
4591 mips_nop (code);
4593 if (is_ordered)
4594 mips_patch (buf, (guint32)code);
4595 break;
4597 case OP_CKFINITE: {
4598 guint32 *branch_patch;
4600 mips_mfc1 (code, mips_at, ins->sreg1+1);
4601 mips_srl (code, mips_at, mips_at, 16+4);
4602 mips_andi (code, mips_at, mips_at, 2047);
4603 mips_addiu (code, mips_at, mips_at, -2047);
4605 branch_patch = (guint32 *)(void *)code;
4606 mips_bne (code, mips_at, mips_zero, 0);
4607 mips_nop (code);
4609 EMIT_SYSTEM_EXCEPTION_NAME("ArithmeticException");
4610 mips_patch (branch_patch, (guint32)code);
4611 mips_fmovd (code, ins->dreg, ins->sreg1);
4612 break;
4614 case OP_JUMP_TABLE:
4615 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
4616 mips_load (code, ins->dreg, 0x0f0f0f0f);
4617 break;
4620 default:
4621 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4622 g_assert_not_reached ();
4625 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4626 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
4627 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
4628 g_assert_not_reached ();
4631 cpos += max_len;
4633 last_ins = ins;
4634 last_offset = offset;
4637 cfg->code_len = code - cfg->native_code;
4640 void
4641 mono_arch_register_lowlevel_calls (void)
4645 void
4646 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, MonoCodeManager *dyn_code_mp, gboolean run_cctors)
4648 MonoJumpInfo *patch_info;
4650 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4651 unsigned char *ip = patch_info->ip.i + code;
4652 const unsigned char *target = NULL;
4654 switch (patch_info->type) {
4655 case MONO_PATCH_INFO_IP:
4656 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)ip);
4657 continue;
4658 case MONO_PATCH_INFO_SWITCH: {
4659 gpointer *table = (gpointer *)patch_info->data.table->table;
4660 int i;
4662 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)table);
4664 for (i = 0; i < patch_info->data.table->table_size; i++) {
4665 table [i] = (int)patch_info->data.table->table [i] + code;
4667 continue;
4669 case MONO_PATCH_INFO_METHODCONST:
4670 case MONO_PATCH_INFO_CLASS:
4671 case MONO_PATCH_INFO_IMAGE:
4672 case MONO_PATCH_INFO_FIELD:
4673 case MONO_PATCH_INFO_VTABLE:
4674 case MONO_PATCH_INFO_IID:
4675 case MONO_PATCH_INFO_SFLDA:
4676 case MONO_PATCH_INFO_LDSTR:
4677 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4678 case MONO_PATCH_INFO_LDTOKEN:
4679 case MONO_PATCH_INFO_R4:
4680 case MONO_PATCH_INFO_R8:
4681 /* from OP_AOTCONST : lui + addiu */
4682 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4683 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)target);
4684 continue;
4685 #if 0
4686 case MONO_PATCH_INFO_EXC_NAME:
4687 g_assert_not_reached ();
4688 *((gconstpointer *)(void *)(ip + 1)) = patch_info->data.name;
4689 continue;
4690 #endif
4691 case MONO_PATCH_INFO_NONE:
4692 /* everything is dealt with at epilog output time */
4693 continue;
4694 default:
4695 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4696 mips_patch ((guint32 *)(void *)ip, (guint32)target);
4697 break;
4703 * Allow tracing to work with this interface (with an optional argument)
4705 * This code is expected to be inserted just after the 'real' prolog code,
4706 * and before the first basic block. We need to allocate a 2nd, temporary
4707 * stack frame so that we can preserve f12-f15 as well as a0-a3.
4710 void*
4711 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4713 guchar *code = p;
4714 int offset = cfg->arch.tracing_offset;
4716 mips_nop (code);
4717 mips_nop (code);
4718 mips_nop (code);
4720 MIPS_SW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4721 MIPS_SW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4722 MIPS_SW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4723 MIPS_SW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4724 #if _MIPS_SIM == _ABIN32
4725 NOT_IMPLEMENTED;
4726 /* FIXME: Need a separate region for these */
4727 MIPS_SW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4728 MIPS_SW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4729 MIPS_SW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4730 MIPS_SW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4732 #endif
4734 mips_load_const (code, mips_a0, cfg->method);
4735 mips_addiu (code, mips_a1, mips_sp, offset);
4736 mips_call (code, mips_t9, func);
4737 mips_nop (code);
4739 MIPS_LW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4740 MIPS_LW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4741 MIPS_LW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4742 MIPS_LW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4743 #if _MIPS_SIM == _ABIN32
4744 NOT_IMPLEMENTED;
4746 MIPS_LW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4747 MIPS_LW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4748 MIPS_LW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4749 MIPS_LW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4751 #endif
4753 mips_nop (code);
4754 mips_nop (code);
4755 mips_nop (code);
4756 return code;
4759 void
4760 mips_adjust_stackframe(MonoCompile *cfg)
4762 MonoBasicBlock *bb;
4763 int delta, threshold, i;
4764 MonoMethodSignature *sig;
4765 int ra_offset;
4767 if (cfg->stack_offset == cfg->arch.local_alloc_offset)
4768 return;
4770 /* adjust cfg->stack_offset for account for down-spilling */
4771 cfg->stack_offset += SIZEOF_REGISTER;
4773 /* re-align cfg->stack_offset if needed (due to var spilling) */
4774 cfg->stack_offset = (cfg->stack_offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
4775 delta = cfg->stack_offset - cfg->arch.local_alloc_offset;
4776 if (cfg->verbose_level > 2) {
4777 g_print ("mips_adjust_stackframe:\n");
4778 g_print ("\tspillvars allocated 0x%x -> 0x%x\n", cfg->arch.local_alloc_offset, cfg->stack_offset);
4780 threshold = cfg->arch.local_alloc_offset;
4781 ra_offset = cfg->stack_offset - sizeof(gpointer);
4782 if (cfg->verbose_level > 2) {
4783 g_print ("\tra_offset %d/0x%x delta %d/0x%x\n", ra_offset, ra_offset, delta, delta);
4786 sig = mono_method_signature (cfg->method);
4787 if (sig && sig->ret && MONO_TYPE_ISSTRUCT (sig->ret)) {
4788 cfg->vret_addr->inst_offset += delta;
4790 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4791 MonoInst *inst = cfg->args [i];
4793 inst->inst_offset += delta;
4797 * loads and stores based off the frame reg that (used to) lie
4798 * above the spill var area need to be increased by 'delta'
4799 * to make room for the spill vars.
4801 /* Need to find loads and stores to adjust that
4802 * are above where the spillvars were inserted, but
4803 * which are not the spillvar references themselves.
4805 * Idea - since all offsets from fp are positive, make
4806 * spillvar offsets negative to begin with so we can spot
4807 * them here.
4810 #if 1
4811 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4812 int ins_cnt = 0;
4813 MonoInst *ins;
4815 if (cfg->verbose_level > 2) {
4816 g_print ("BASIC BLOCK %d:\n", bb->block_num);
4818 MONO_BB_FOR_EACH_INS (bb, ins) {
4819 int adj_c0 = 0;
4820 int adj_imm = 0;
4822 if (cfg->verbose_level > 2) {
4823 mono_print_ins_index (ins_cnt, ins);
4825 /* The == mips_sp tests catch FP spills */
4826 if (MONO_IS_LOAD_MEMBASE(ins) && ((ins->inst_basereg == mips_fp) ||
4827 (ins->inst_basereg == mips_sp))) {
4828 switch (ins->opcode) {
4829 case OP_LOADI8_MEMBASE:
4830 case OP_LOADR8_MEMBASE:
4831 adj_c0 = 8;
4832 break;
4833 default:
4834 adj_c0 = 4;
4835 break;
4837 } else if (MONO_IS_STORE_MEMBASE(ins) && ((ins->dreg == mips_fp) ||
4838 (ins->dreg == mips_sp))) {
4839 switch (ins->opcode) {
4840 case OP_STOREI8_MEMBASE_REG:
4841 case OP_STORER8_MEMBASE_REG:
4842 case OP_STOREI8_MEMBASE_IMM:
4843 adj_c0 = 8;
4844 break;
4845 default:
4846 adj_c0 = 4;
4847 break;
4850 if (((ins->opcode == OP_ADD_IMM) || (ins->opcode == OP_IADD_IMM)) && (ins->sreg1 == cfg->frame_reg))
4851 adj_imm = 1;
4852 if (adj_c0) {
4853 if (ins->inst_c0 >= threshold) {
4854 ins->inst_c0 += delta;
4855 if (cfg->verbose_level > 2) {
4856 g_print ("adj");
4857 mono_print_ins_index (ins_cnt, ins);
4860 else if (ins->inst_c0 < 0) {
4861 /* Adj_c0 holds the size of the datatype. */
4862 ins->inst_c0 = - ins->inst_c0 - adj_c0;
4863 if (cfg->verbose_level > 2) {
4864 g_print ("spill");
4865 mono_print_ins_index (ins_cnt, ins);
4868 g_assert (ins->inst_c0 != ra_offset);
4870 if (adj_imm) {
4871 if (ins->inst_imm >= threshold) {
4872 ins->inst_imm += delta;
4873 if (cfg->verbose_level > 2) {
4874 g_print ("adj");
4875 mono_print_ins_index (ins_cnt, ins);
4878 g_assert (ins->inst_c0 != ra_offset);
4881 ++ins_cnt;
4884 #endif
4888 * Stack frame layout:
4890 * ------------------- sp + cfg->stack_usage + cfg->param_area
4891 * param area incoming
4892 * ------------------- sp + cfg->stack_usage + MIPS_STACK_PARAM_OFFSET
4893 * a0-a3 incoming
4894 * ------------------- sp + cfg->stack_usage
4895 * ra
4896 * ------------------- sp + cfg->stack_usage-4
4897 * spilled regs
4898 * ------------------- sp +
4899 * MonoLMF structure optional
4900 * ------------------- sp + cfg->arch.lmf_offset
4901 * saved registers s0-s8
4902 * ------------------- sp + cfg->arch.iregs_offset
4903 * locals
4904 * ------------------- sp + cfg->param_area
4905 * param area outgoing
4906 * ------------------- sp + MIPS_STACK_PARAM_OFFSET
4907 * a0-a3 outgoing
4908 * ------------------- sp
4909 * red zone
4911 guint8 *
4912 mono_arch_emit_prolog (MonoCompile *cfg)
4914 MonoMethod *method = cfg->method;
4915 MonoMethodSignature *sig;
4916 MonoInst *inst;
4917 int alloc_size, pos, i, max_offset;
4918 int alloc2_size = 0;
4919 guint8 *code;
4920 CallInfo *cinfo;
4921 int tracing = 0;
4922 guint32 iregs_to_save = 0;
4923 #if SAVE_FP_REGS
4924 guint32 fregs_to_save = 0;
4925 #endif
4926 /* lmf_offset is the offset of the LMF from our stack pointer. */
4927 guint32 lmf_offset = cfg->arch.lmf_offset;
4928 int cfa_offset = 0;
4929 MonoBasicBlock *bb;
4931 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4932 tracing = 1;
4934 if (tracing)
4935 cfg->flags |= MONO_CFG_HAS_CALLS;
4937 sig = mono_method_signature (method);
4938 cfg->code_size = 768 + sig->param_count * 20;
4939 code = cfg->native_code = g_malloc (cfg->code_size);
4942 * compute max_offset in order to use short forward jumps.
4944 max_offset = 0;
4945 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4946 MonoInst *ins = bb->code;
4947 bb->max_offset = max_offset;
4949 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
4950 max_offset += 6;
4952 MONO_BB_FOR_EACH_INS (bb, ins)
4953 max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
4955 if (max_offset > 0xffff)
4956 cfg->arch.long_branch = TRUE;
4959 * Currently, fp points to the bottom of the frame on MIPS, unlike other platforms.
4960 * This means that we have to adjust the offsets inside instructions which reference
4961 * arguments received on the stack, since the initial offset doesn't take into
4962 * account spill slots.
4964 mips_adjust_stackframe (cfg);
4966 /* Offset between current sp and the CFA */
4967 cfa_offset = 0;
4968 mono_emit_unwind_op_def_cfa (cfg, code, mips_sp, cfa_offset);
4970 /* stack_offset should not be changed here. */
4971 alloc_size = cfg->stack_offset;
4972 cfg->stack_usage = alloc_size;
4974 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
4975 #if SAVE_FP_REGS
4976 #if 0
4977 fregs_to_save = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
4978 #else
4979 fregs_to_save = MONO_ARCH_CALLEE_SAVED_FREGS;
4980 fregs_to_save |= (fregs_to_save << 1);
4981 #endif
4982 #endif
4983 /* If the stack size is too big, save 1024 bytes to start with
4984 * so the prologue can use imm16(reg) addressing, then allocate
4985 * the rest of the frame.
4987 if (alloc_size > ((1 << 15) - 1024)) {
4988 alloc2_size = alloc_size - 1024;
4989 alloc_size = 1024;
4991 if (alloc_size) {
4992 g_assert (mips_is_imm16 (-alloc_size));
4993 mips_addiu (code, mips_sp, mips_sp, -alloc_size);
4994 cfa_offset = alloc_size;
4995 mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
4998 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
4999 int offset = alloc_size + MIPS_RET_ADDR_OFFSET;
5000 if (mips_is_imm16(offset))
5001 mips_sw (code, mips_ra, mips_sp, offset);
5002 else {
5003 g_assert_not_reached ();
5005 /* sp = cfa - cfa_offset, so sp + offset = cfa - cfa_offset + offset */
5006 mono_emit_unwind_op_offset (cfg, code, mips_ra, offset - cfa_offset);
5009 /* XXX - optimize this later to not save all regs if LMF constructed */
5010 pos = cfg->arch.iregs_offset - alloc2_size;
5012 if (iregs_to_save) {
5013 /* save used registers in own stack frame (at pos) */
5014 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5015 if (iregs_to_save & (1 << i)) {
5016 g_assert (pos < (int)(cfg->stack_usage - sizeof(gpointer)));
5017 g_assert (mips_is_imm16(pos));
5018 MIPS_SW (code, i, mips_sp, pos);
5019 mono_emit_unwind_op_offset (cfg, code, i, pos - cfa_offset);
5020 pos += SIZEOF_REGISTER;
5025 // FIXME: Don't save registers twice if there is an LMF
5026 // s8 has to be special cased since it is overwritten with the updated value
5027 // below
5028 if (method->save_lmf) {
5029 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5030 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[i]);
5031 g_assert (mips_is_imm16(offset));
5032 if (MIPS_LMF_IREGMASK & (1 << i))
5033 MIPS_SW (code, i, mips_sp, offset);
5037 #if SAVE_FP_REGS
5038 /* Save float registers */
5039 if (fregs_to_save) {
5040 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5041 if (fregs_to_save & (1 << i)) {
5042 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
5043 g_assert (mips_is_imm16(pos));
5044 mips_swc1 (code, i, mips_sp, pos);
5045 pos += sizeof (gulong);
5050 if (method->save_lmf) {
5051 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5052 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, fregs[i]);
5053 g_assert (mips_is_imm16(offset));
5054 mips_swc1 (code, i, mips_sp, offset);
5058 #endif
5059 if (cfg->frame_reg != mips_sp) {
5060 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
5061 mono_emit_unwind_op_def_cfa (cfg, code, cfg->frame_reg, cfa_offset);
5063 if (method->save_lmf) {
5064 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[cfg->frame_reg]);
5065 g_assert (mips_is_imm16(offset));
5066 MIPS_SW (code, cfg->frame_reg, mips_sp, offset);
5070 /* store runtime generic context */
5071 if (cfg->rgctx_var) {
5072 MonoInst *ins = cfg->rgctx_var;
5074 g_assert (ins->opcode == OP_REGOFFSET);
5076 g_assert (mips_is_imm16 (ins->inst_offset));
5077 mips_sw (code, MONO_ARCH_RGCTX_REG, ins->inst_basereg, ins->inst_offset);
5080 /* load arguments allocated to register from the stack */
5081 pos = 0;
5083 if (!cfg->arch.cinfo)
5084 cfg->arch.cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
5085 cinfo = cfg->arch.cinfo;
5087 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
5088 ArgInfo *ainfo = &cinfo->ret;
5089 inst = cfg->vret_addr;
5090 if (inst->opcode == OP_REGVAR)
5091 MIPS_MOVE (code, inst->dreg, ainfo->reg);
5092 else if (mips_is_imm16 (inst->inst_offset)) {
5093 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5094 } else {
5095 mips_load_const (code, mips_at, inst->inst_offset);
5096 mips_addu (code, mips_at, mips_at, inst->inst_basereg);
5097 mips_sw (code, ainfo->reg, mips_at, 0);
5101 if (sig->call_convention == MONO_CALL_VARARG) {
5102 ArgInfo *cookie = &cinfo->sig_cookie;
5103 int offset = alloc_size + cookie->offset;
5105 /* Save the sig cookie address */
5106 g_assert (cookie->storage == ArgOnStack);
5108 g_assert (mips_is_imm16(offset));
5109 mips_addi (code, mips_at, cfg->frame_reg, offset);
5110 mips_sw (code, mips_at, cfg->frame_reg, cfg->sig_cookie - alloc2_size);
5113 /* Keep this in sync with emit_load_volatile_arguments */
5114 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
5115 ArgInfo *ainfo = cinfo->args + i;
5116 inst = cfg->args [pos];
5118 if (cfg->verbose_level > 2)
5119 g_print ("Saving argument %d (type: %d)\n", i, ainfo->storage);
5120 if (inst->opcode == OP_REGVAR) {
5121 /* Argument ends up in a register */
5122 if (ainfo->storage == ArgInIReg)
5123 MIPS_MOVE (code, inst->dreg, ainfo->reg);
5124 else if (ainfo->storage == ArgInFReg) {
5125 g_assert_not_reached();
5126 #if 0
5127 ppc_fmr (code, inst->dreg, ainfo->reg);
5128 #endif
5130 else if (ainfo->storage == ArgOnStack) {
5131 int offset = cfg->stack_usage + ainfo->offset;
5132 g_assert (mips_is_imm16(offset));
5133 mips_lw (code, inst->dreg, mips_sp, offset);
5134 } else
5135 g_assert_not_reached ();
5137 if (cfg->verbose_level > 2)
5138 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
5139 } else {
5140 /* Argument ends up on the stack */
5141 if (ainfo->storage == ArgInIReg) {
5142 int basereg_offset;
5143 /* Incoming parameters should be above this frame */
5144 if (cfg->verbose_level > 2)
5145 g_print ("stack slot at %d of %d+%d\n",
5146 inst->inst_offset, alloc_size, alloc2_size);
5147 /* g_assert (inst->inst_offset >= alloc_size); */
5148 g_assert (inst->inst_basereg == cfg->frame_reg);
5149 basereg_offset = inst->inst_offset - alloc2_size;
5150 g_assert (mips_is_imm16 (basereg_offset));
5151 switch (ainfo->size) {
5152 case 1:
5153 mips_sb (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5154 break;
5155 case 2:
5156 mips_sh (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5157 break;
5158 case 0: /* XXX */
5159 case 4:
5160 mips_sw (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5161 break;
5162 case 8:
5163 #if (SIZEOF_REGISTER == 4)
5164 mips_sw (code, ainfo->reg, inst->inst_basereg, basereg_offset + ls_word_offset);
5165 mips_sw (code, ainfo->reg + 1, inst->inst_basereg, basereg_offset + ms_word_offset);
5166 #elif (SIZEOF_REGISTER == 8)
5167 mips_sd (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5168 #endif
5169 break;
5170 default:
5171 g_assert_not_reached ();
5172 break;
5174 } else if (ainfo->storage == ArgOnStack) {
5176 * Argument comes in on the stack, and ends up on the stack
5177 * 1 and 2 byte args are passed as 32-bit quantities, but used as
5178 * 8 and 16 bit quantities. Shorten them in place.
5180 g_assert (mips_is_imm16 (inst->inst_offset));
5181 switch (ainfo->size) {
5182 case 1:
5183 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
5184 mips_sb (code, mips_at, inst->inst_basereg, inst->inst_offset);
5185 break;
5186 case 2:
5187 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
5188 mips_sh (code, mips_at, inst->inst_basereg, inst->inst_offset);
5189 break;
5190 case 0: /* XXX */
5191 case 4:
5192 case 8:
5193 break;
5194 default:
5195 g_assert_not_reached ();
5197 } else if (ainfo->storage == ArgInFReg) {
5198 g_assert (mips_is_imm16 (inst->inst_offset));
5199 g_assert (mips_is_imm16 (inst->inst_offset+4));
5200 if (ainfo->size == 8) {
5201 #if _MIPS_SIM == _ABIO32
5202 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
5203 mips_swc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
5204 #elif _MIPS_SIM == _ABIN32
5205 mips_sdc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5206 #endif
5208 else if (ainfo->size == 4)
5209 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5210 else
5211 g_assert_not_reached ();
5212 } else if (ainfo->storage == ArgStructByVal) {
5213 int i;
5214 int doffset = inst->inst_offset;
5216 g_assert (mips_is_imm16 (inst->inst_offset));
5217 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
5218 /* Push the argument registers into their stack slots */
5219 for (i = 0; i < ainfo->size; ++i) {
5220 g_assert (mips_is_imm16(doffset));
5221 MIPS_SW (code, ainfo->reg + i, inst->inst_basereg, doffset);
5222 doffset += SIZEOF_REGISTER;
5224 } else if (ainfo->storage == ArgStructByAddr) {
5225 g_assert (mips_is_imm16 (inst->inst_offset));
5226 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
5227 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
5228 } else
5229 g_assert_not_reached ();
5231 pos++;
5234 if (method->save_lmf) {
5235 mips_load_const (code, mips_at, MIPS_LMF_MAGIC1);
5236 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, magic));
5238 if (lmf_pthread_key != -1) {
5239 g_assert_not_reached();
5240 #if 0
5241 emit_tls_access (code, mips_temp, lmf_pthread_key);
5242 #endif
5243 if (G_STRUCT_OFFSET (MonoJitTlsData, lmf)) {
5244 int offset = G_STRUCT_OFFSET (MonoJitTlsData, lmf);
5245 g_assert (mips_is_imm16(offset));
5246 mips_addiu (code, mips_a0, mips_temp, offset);
5248 } else {
5249 /* This can/will clobber the a0-a3 registers */
5250 mips_call (code, mips_t9, (gpointer)mono_get_lmf_addr);
5253 /* mips_v0 is the result from mono_get_lmf_addr () (MonoLMF **) */
5254 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5255 mips_sw (code, mips_v0, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5256 /* new_lmf->previous_lmf = *lmf_addr */
5257 mips_lw (code, mips_at, mips_v0, 0);
5258 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5259 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5260 /* *(lmf_addr) = sp + lmf_offset */
5261 g_assert (mips_is_imm16(lmf_offset));
5262 mips_addiu (code, mips_at, mips_sp, lmf_offset);
5263 mips_sw (code, mips_at, mips_v0, 0);
5265 /* save method info */
5266 mips_load_const (code, mips_at, method);
5267 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, method)));
5268 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, method));
5270 /* save the current IP */
5271 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5272 mips_load_const (code, mips_at, 0x01010101);
5273 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, eip));
5276 if (alloc2_size) {
5277 if (mips_is_imm16 (-alloc2_size)) {
5278 mips_addu (code, mips_sp, mips_sp, -alloc2_size);
5280 else {
5281 mips_load_const (code, mips_at, -alloc2_size);
5282 mips_addu (code, mips_sp, mips_sp, mips_at);
5284 alloc_size += alloc2_size;
5285 cfa_offset += alloc2_size;
5286 if (cfg->frame_reg != mips_sp)
5287 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
5288 else
5289 mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
5292 if (tracing) {
5293 #if _MIPS_SIM == _ABIO32
5294 cfg->arch.tracing_offset = cfg->stack_offset;
5295 #elif _MIPS_SIM == _ABIN32
5296 /* no stack slots by default for argument regs, reserve a special block */
5297 g_assert_not_reached ();
5298 #endif
5299 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
5302 cfg->code_len = code - cfg->native_code;
5303 g_assert (cfg->code_len < cfg->code_size);
5305 return code;
5308 enum {
5309 SAVE_NONE,
5310 SAVE_STRUCT,
5311 SAVE_ONE,
5312 SAVE_TWO,
5313 SAVE_FP
5316 void*
5317 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
5319 guchar *code = p;
5320 int save_mode = SAVE_NONE;
5321 int offset;
5322 MonoMethod *method = cfg->method;
5323 int rtype = mini_type_get_underlying_type (cfg->generic_sharing_context, mono_method_signature (method)->ret)->type;
5324 int save_offset = MIPS_STACK_PARAM_OFFSET;
5326 g_assert ((save_offset & (MIPS_STACK_ALIGNMENT-1)) == 0);
5328 offset = code - cfg->native_code;
5329 /* we need about 16 instructions */
5330 if (offset > (cfg->code_size - 16 * 4)) {
5331 cfg->code_size *= 2;
5332 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5333 code = cfg->native_code + offset;
5335 mips_nop (code);
5336 mips_nop (code);
5337 switch (rtype) {
5338 case MONO_TYPE_VOID:
5339 /* special case string .ctor icall */
5340 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
5341 save_mode = SAVE_ONE;
5342 else
5343 save_mode = SAVE_NONE;
5344 break;
5345 case MONO_TYPE_R4:
5346 case MONO_TYPE_R8:
5347 save_mode = SAVE_FP;
5348 break;
5349 case MONO_TYPE_VALUETYPE:
5350 save_mode = SAVE_STRUCT;
5351 break;
5352 case MONO_TYPE_I8:
5353 case MONO_TYPE_U8:
5354 #if SIZEOF_REGISTER == 4
5355 save_mode = SAVE_TWO;
5356 #elif SIZEOF_REGISTER == 8
5357 save_mode = SAVE_ONE;
5358 #endif
5359 break;
5360 default:
5361 save_mode = SAVE_ONE;
5362 break;
5365 mips_addiu (code, mips_sp, mips_sp, -32);
5366 g_assert (mips_is_imm16(save_offset));
5367 switch (save_mode) {
5368 case SAVE_TWO:
5369 mips_sw (code, mips_v0, mips_sp, save_offset);
5370 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5371 mips_sw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5372 if (enable_arguments) {
5373 MIPS_MOVE (code, mips_a1, mips_v0);
5374 MIPS_MOVE (code, mips_a2, mips_v1);
5376 break;
5377 case SAVE_ONE:
5378 MIPS_SW (code, mips_v0, mips_sp, save_offset);
5379 if (enable_arguments) {
5380 MIPS_MOVE (code, mips_a1, mips_v0);
5382 break;
5383 case SAVE_FP:
5384 mips_sdc1 (code, mips_f0, mips_sp, save_offset);
5385 mips_ldc1 (code, mips_f12, mips_sp, save_offset);
5386 mips_lw (code, mips_a0, mips_sp, save_offset);
5387 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5388 mips_lw (code, mips_a1, mips_sp, save_offset + SIZEOF_REGISTER);
5389 break;
5390 case SAVE_STRUCT:
5391 case SAVE_NONE:
5392 default:
5393 break;
5395 mips_load_const (code, mips_a0, cfg->method);
5396 mips_call (code, mips_t9, func);
5398 switch (save_mode) {
5399 case SAVE_TWO:
5400 mips_lw (code, mips_v0, mips_sp, save_offset);
5401 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5402 mips_lw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5403 break;
5404 case SAVE_ONE:
5405 MIPS_LW (code, mips_v0, mips_sp, save_offset);
5406 break;
5407 case SAVE_FP:
5408 mips_ldc1 (code, mips_f0, mips_sp, save_offset);
5409 break;
5410 case SAVE_STRUCT:
5411 case SAVE_NONE:
5412 default:
5413 break;
5415 mips_addiu (code, mips_sp, mips_sp, 32);
5416 mips_nop (code);
5417 mips_nop (code);
5418 return code;
5421 guint8 *
5422 mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code)
5424 MonoMethod *method = cfg->method;
5425 int pos = 0, i;
5426 int max_epilog_size = 16 + 20*4;
5427 int alloc2_size = 0;
5428 guint32 iregs_to_restore;
5429 #if SAVE_FP_REGS
5430 guint32 fregs_to_restore;
5431 #endif
5433 if (cfg->method->save_lmf)
5434 max_epilog_size += 128;
5436 if (mono_jit_trace_calls != NULL)
5437 max_epilog_size += 50;
5439 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5440 max_epilog_size += 50;
5442 if (code)
5443 pos = code - cfg->native_code;
5444 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5445 cfg->code_size *= 2;
5446 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5447 cfg->stat_code_reallocs++;
5451 * Keep in sync with OP_JMP
5453 if (code)
5454 code = cfg->native_code + pos;
5455 else
5456 code = cfg->native_code + cfg->code_len;
5458 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5459 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5461 if (cfg->frame_reg != mips_sp) {
5462 MIPS_MOVE (code, mips_sp, cfg->frame_reg);
5464 /* If the stack frame is really large, deconstruct it in two steps */
5465 if (cfg->stack_usage > ((1 << 15) - 1024)) {
5466 alloc2_size = cfg->stack_usage - 1024;
5467 /* partially deconstruct the stack */
5468 mips_load_const (code, mips_at, alloc2_size);
5469 mips_addu (code, mips_sp, mips_sp, mips_at);
5471 pos = cfg->arch.iregs_offset - alloc2_size;
5472 iregs_to_restore = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
5473 if (iregs_to_restore) {
5474 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5475 if (iregs_to_restore & (1 << i)) {
5476 g_assert (mips_is_imm16(pos));
5477 MIPS_LW (code, i, mips_sp, pos);
5478 pos += SIZEOF_REGISTER;
5483 #if SAVE_FP_REGS
5484 #if 0
5485 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
5486 #else
5487 fregs_to_restore = MONO_ARCH_CALLEE_SAVED_FREGS;
5488 fregs_to_restore |= (fregs_to_restore << 1);
5489 #endif
5490 if (fregs_to_restore) {
5491 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5492 if (fregs_to_restore & (1 << i)) {
5493 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
5494 g_assert (mips_is_imm16(pos));
5495 mips_lwc1 (code, i, mips_sp, pos);
5496 pos += FREG_SIZE
5500 #endif
5502 /* Unlink the LMF if necessary */
5503 if (method->save_lmf) {
5504 int lmf_offset = cfg->arch.lmf_offset;
5506 /* t0 = current_lmf->previous_lmf */
5507 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5508 mips_lw (code, mips_temp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5509 /* t1 = lmf_addr */
5510 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5511 mips_lw (code, mips_t1, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5512 /* (*lmf_addr) = previous_lmf */
5513 mips_sw (code, mips_temp, mips_t1, 0);
5516 #if 0
5517 /* Restore the fp */
5518 mips_lw (code, mips_fp, mips_sp, cfg->stack_usage + MIPS_FP_ADDR_OFFSET);
5519 #endif
5520 /* Restore ra */
5521 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
5522 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET));
5523 mips_lw (code, mips_ra, mips_sp, cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET);
5525 /* Restore the stack pointer */
5526 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size));
5527 mips_addiu (code, mips_sp, mips_sp, cfg->stack_usage - alloc2_size);
5529 /* Caller will emit either return or tail-call sequence */
5531 cfg->code_len = code - cfg->native_code;
5533 g_assert (cfg->code_len < cfg->code_size);
5534 return (code);
5537 void
5538 mono_arch_emit_epilog (MonoCompile *cfg)
5540 guint8 *code;
5542 code = mono_arch_emit_epilog_sub (cfg, NULL);
5544 mips_jr (code, mips_ra);
5545 mips_nop (code);
5547 cfg->code_len = code - cfg->native_code;
5549 g_assert (cfg->code_len < cfg->code_size);
5552 /* remove once throw_exception_by_name is eliminated */
5553 #if 0
5554 static int
5555 exception_id_by_name (const char *name)
5557 if (strcmp (name, "IndexOutOfRangeException") == 0)
5558 return MONO_EXC_INDEX_OUT_OF_RANGE;
5559 if (strcmp (name, "OverflowException") == 0)
5560 return MONO_EXC_OVERFLOW;
5561 if (strcmp (name, "ArithmeticException") == 0)
5562 return MONO_EXC_ARITHMETIC;
5563 if (strcmp (name, "DivideByZeroException") == 0)
5564 return MONO_EXC_DIVIDE_BY_ZERO;
5565 if (strcmp (name, "InvalidCastException") == 0)
5566 return MONO_EXC_INVALID_CAST;
5567 if (strcmp (name, "NullReferenceException") == 0)
5568 return MONO_EXC_NULL_REF;
5569 if (strcmp (name, "ArrayTypeMismatchException") == 0)
5570 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5571 if (strcmp (name, "ArgumentException") == 0)
5572 return MONO_EXC_ARGUMENT;
5573 g_error ("Unknown intrinsic exception %s\n", name);
5574 return 0;
5576 #endif
5578 void
5579 mono_arch_emit_exceptions (MonoCompile *cfg)
5581 #if 0
5582 MonoJumpInfo *patch_info;
5583 int i;
5584 guint8 *code;
5585 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
5586 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
5587 int max_epilog_size = 50;
5589 /* count the number of exception infos */
5592 * make sure we have enough space for exceptions
5593 * 24 is the simulated call to throw_exception_by_name
5595 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5596 #if 0
5597 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5598 i = exception_id_by_name (patch_info->data.target);
5599 g_assert (i < MONO_EXC_INTRINS_NUM);
5600 if (!exc_throw_found [i]) {
5601 max_epilog_size += 12;
5602 exc_throw_found [i] = TRUE;
5605 #endif
5608 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5609 cfg->code_size *= 2;
5610 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5611 cfg->stat_code_reallocs++;
5614 code = cfg->native_code + cfg->code_len;
5616 /* add code to raise exceptions */
5617 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5618 switch (patch_info->type) {
5619 case MONO_PATCH_INFO_EXC: {
5620 #if 0
5621 //unsigned char *ip = patch_info->ip.i + cfg->native_code;
5623 i = exception_id_by_name (patch_info->data.target);
5624 g_assert (i >= 0 && i < MONO_EXC_INTRINS_NUM);
5625 if (!exc_throw_pos [i]) {
5626 guint32 addr;
5628 exc_throw_pos [i] = code;
5629 //g_print ("exc: writing stub at %p\n", code);
5630 mips_load_const (code, mips_a0, patch_info->data.target);
5631 addr = (guint32) mono_arch_get_throw_exception_by_name ();
5632 mips_load_const (code, mips_t9, addr);
5633 mips_jr (code, mips_t9);
5634 mips_nop (code);
5636 //g_print ("exc: patch %p to %p\n", ip, exc_throw_pos[i]);
5638 /* Turn into a Relative patch, pointing at code stub */
5639 patch_info->type = MONO_PATCH_INFO_METHOD_REL;
5640 patch_info->data.offset = exc_throw_pos[i] - cfg->native_code;
5641 #else
5642 g_assert_not_reached();
5643 #endif
5644 break;
5646 default:
5647 /* do nothing */
5648 break;
5652 cfg->code_len = code - cfg->native_code;
5654 g_assert (cfg->code_len < cfg->code_size);
5655 #endif
5659 * Thread local storage support
5661 static void
5662 setup_tls_access (void)
5664 guint32 ptk;
5665 //guint32 *ins, *code;
5667 if (tls_mode == TLS_MODE_FAILED)
5668 return;
5670 if (g_getenv ("MONO_NO_TLS")) {
5671 tls_mode = TLS_MODE_FAILED;
5672 return;
5675 if (tls_mode == TLS_MODE_DETECT) {
5676 /* XXX */
5677 tls_mode = TLS_MODE_FAILED;
5678 return;
5679 #if 0
5681 ins = (guint32*)pthread_getspecific;
5682 /* uncond branch to the real method */
5683 if ((*ins >> 26) == 18) {
5684 gint32 val;
5685 val = (*ins & ~3) << 6;
5686 val >>= 6;
5687 if (*ins & 2) {
5688 /* absolute */
5689 ins = (guint32*)val;
5690 } else {
5691 ins = (guint32*) ((char*)ins + val);
5694 code = &cmplwi_1023;
5695 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
5696 code = &li_0x48;
5697 ppc_li (code, ppc_r4, 0x48);
5698 code = &blr_ins;
5699 ppc_blr (code);
5700 if (*ins == cmplwi_1023) {
5701 int found_lwz_284 = 0;
5702 for (ptk = 0; ptk < 20; ++ptk) {
5703 ++ins;
5704 if (!*ins || *ins == blr_ins)
5705 break;
5706 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
5707 found_lwz_284 = 1;
5708 break;
5711 if (!found_lwz_284) {
5712 tls_mode = TLS_MODE_FAILED;
5713 return;
5715 tls_mode = TLS_MODE_LTHREADS;
5716 } else if (*ins == li_0x48) {
5717 ++ins;
5718 /* uncond branch to the real method */
5719 if ((*ins >> 26) == 18) {
5720 gint32 val;
5721 val = (*ins & ~3) << 6;
5722 val >>= 6;
5723 if (*ins & 2) {
5724 /* absolute */
5725 ins = (guint32*)val;
5726 } else {
5727 ins = (guint32*) ((char*)ins + val);
5729 code = &val;
5730 ppc_li (code, ppc_r0, 0x7FF2);
5731 if (ins [1] == val) {
5732 /* Darwin on G4, implement */
5733 tls_mode = TLS_MODE_FAILED;
5734 return;
5735 } else {
5736 code = &val;
5737 ppc_mfspr (code, ppc_r3, 104);
5738 if (ins [1] != val) {
5739 tls_mode = TLS_MODE_FAILED;
5740 return;
5742 tls_mode = TLS_MODE_DARWIN_G5;
5744 } else {
5745 tls_mode = TLS_MODE_FAILED;
5746 return;
5748 } else {
5749 tls_mode = TLS_MODE_FAILED;
5750 return;
5752 #endif
5754 if (monodomain_key == -1) {
5755 ptk = mono_domain_get_tls_key ();
5756 if (ptk < 1024)
5757 monodomain_key = ptk;
5759 if (lmf_pthread_key == -1) {
5760 ptk = mono_jit_tls_id;
5761 if (ptk < 1024) {
5762 /*g_print ("MonoLMF at: %d\n", ptk);*/
5763 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
5764 init_tls_failed = 1;
5765 return;
5767 lmf_pthread_key = ptk;
5770 if (monothread_key == -1) {
5771 ptk = mono_thread_get_tls_key ();
5772 if (ptk < 1024) {
5773 monothread_key = ptk;
5774 /*g_print ("thread inited: %d\n", ptk);*/
5775 } else {
5776 /*g_print ("thread not inited yet %d\n", ptk);*/
5781 void
5782 mono_arch_finish_init (void)
5784 setup_tls_access ();
5787 void
5788 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5792 void
5793 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
5795 int this_dreg = mips_a0;
5797 if (vt_reg != -1)
5798 this_dreg = mips_a1;
5800 /* add the this argument */
5801 if (this_reg != -1) {
5802 MonoInst *this;
5803 MONO_INST_NEW (cfg, this, OP_MOVE);
5804 this->type = this_type;
5805 this->sreg1 = this_reg;
5806 this->dreg = mono_alloc_ireg (cfg);
5807 mono_bblock_add_inst (cfg->cbb, this);
5808 mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE);
5811 if (vt_reg != -1) {
5812 MonoInst *vtarg;
5813 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
5814 vtarg->type = STACK_MP;
5815 vtarg->sreg1 = vt_reg;
5816 vtarg->dreg = mono_alloc_ireg (cfg);
5817 mono_bblock_add_inst (cfg->cbb, vtarg);
5818 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, mips_a0, FALSE);
5822 MonoInst*
5823 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5825 MonoInst *ins = NULL;
5827 return ins;
5830 MonoInst*
5831 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5833 return NULL;
5836 gboolean
5837 mono_arch_print_tree (MonoInst *tree, int arity)
5839 return 0;
5842 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
5844 MonoInst* ins;
5846 setup_tls_access ();
5847 if (monodomain_key == -1)
5848 return NULL;
5850 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5851 ins->inst_offset = monodomain_key;
5852 return ins;
5855 mgreg_t
5856 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5858 return ctx->sc_regs [reg];
5861 #ifdef MONO_ARCH_HAVE_IMT
5863 #define ENABLE_WRONG_METHOD_CHECK 0
5865 #define MIPS_LOAD_SEQUENCE_LENGTH 8
5866 #define CMP_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 4)
5867 #define BR_SIZE 8
5868 #define LOADSTORE_SIZE 4
5869 #define JUMP_IMM_SIZE 16
5870 #define JUMP_IMM32_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 8)
5871 #define LOAD_CONST_SIZE 8
5872 #define JUMP_JR_SIZE 8
5875 * LOCKING: called with the domain lock held
5877 gpointer
5878 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5879 gpointer fail_tramp)
5881 int i;
5882 int size = 0;
5883 guint8 *code, *start, *patch;
5885 for (i = 0; i < count; ++i) {
5886 MonoIMTCheckItem *item = imt_entries [i];
5888 if (item->is_equals) {
5889 if (item->check_target_idx) {
5890 item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_JR_SIZE;
5891 if (item->has_target_code)
5892 item->chunk_size += LOAD_CONST_SIZE;
5893 else
5894 item->chunk_size += LOADSTORE_SIZE;
5895 } else {
5896 if (fail_tramp) {
5897 item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_IMM32_SIZE +
5898 LOADSTORE_SIZE + JUMP_IMM32_SIZE;
5899 if (!item->has_target_code)
5900 item->chunk_size += LOADSTORE_SIZE;
5901 } else {
5902 item->chunk_size += LOADSTORE_SIZE + JUMP_JR_SIZE;
5903 #if ENABLE_WRONG_METHOD_CHECK
5904 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5905 #endif
5908 } else {
5909 item->chunk_size += CMP_SIZE + BR_SIZE;
5910 imt_entries [item->check_target_idx]->compare_done = TRUE;
5912 size += item->chunk_size;
5914 /* the initial load of the vtable address */
5915 size += MIPS_LOAD_SEQUENCE_LENGTH;
5916 if (fail_tramp) {
5917 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5918 } else {
5919 code = mono_domain_code_reserve (domain, size);
5921 start = code;
5923 /* t7 points to the vtable */
5924 mips_load_const (code, mips_t7, (gsize)(& (vtable->vtable [0])));
5926 for (i = 0; i < count; ++i) {
5927 MonoIMTCheckItem *item = imt_entries [i];
5929 item->code_target = code;
5930 if (item->is_equals) {
5931 if (item->check_target_idx) {
5932 mips_load_const (code, mips_temp, (gsize)item->key);
5933 item->jmp_code = code;
5934 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5935 mips_nop (code);
5936 if (item->has_target_code) {
5937 mips_load_const (code, mips_t9,
5938 item->value.target_code);
5940 else {
5941 mips_lw (code, mips_t9, mips_t7,
5942 (sizeof (gpointer) * item->value.vtable_slot));
5944 mips_jr (code, mips_t9);
5945 mips_nop (code);
5946 } else {
5947 if (fail_tramp) {
5948 mips_load_const (code, mips_temp, (gsize)item->key);
5949 patch = code;
5950 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5951 mips_nop (code);
5952 if (item->has_target_code) {
5953 mips_load_const (code, mips_t9,
5954 item->value.target_code);
5955 } else {
5956 g_assert (vtable);
5957 mips_load_const (code, mips_at,
5958 & (vtable->vtable [item->value.vtable_slot]));
5959 mips_lw (code, mips_t9, mips_at, 0);
5961 mips_jr (code, mips_t9);
5962 mips_nop (code);
5963 mips_patch ((guint32 *)(void *)patch, (guint32)code);
5964 mips_load_const (code, mips_t9, fail_tramp);
5965 mips_jr (code, mips_t9);
5966 mips_nop (code);
5967 } else {
5968 /* enable the commented code to assert on wrong method */
5969 #if ENABLE_WRONG_METHOD_CHECK
5970 ppc_load (code, ppc_r0, (guint32)item->key);
5971 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5972 patch = code;
5973 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5974 #endif
5975 mips_lw (code, mips_t9, mips_t7,
5976 (sizeof (gpointer) * item->value.vtable_slot));
5977 mips_jr (code, mips_t9);
5978 mips_nop (code);
5980 #if ENABLE_WRONG_METHOD_CHECK
5981 ppc_patch (patch, code);
5982 ppc_break (code);
5983 #endif
5986 } else {
5987 mips_load_const (code, mips_temp, (gulong)item->key);
5988 mips_slt (code, mips_temp, MONO_ARCH_IMT_REG, mips_temp);
5990 item->jmp_code = code;
5991 mips_beq (code, mips_temp, mips_zero, 0);
5992 mips_nop (code);
5995 /* patch the branches to get to the target items */
5996 for (i = 0; i < count; ++i) {
5997 MonoIMTCheckItem *item = imt_entries [i];
5998 if (item->jmp_code && item->check_target_idx) {
5999 mips_patch ((guint32 *)item->jmp_code,
6000 (guint32)imt_entries [item->check_target_idx]->code_target);
6004 if (!fail_tramp)
6005 mono_stats.imt_thunks_size += code - start;
6006 g_assert (code - start <= size);
6007 mono_arch_flush_icache (start, size);
6008 return start;
6011 MonoMethod*
6012 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
6014 return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
6016 #endif
6018 MonoVTable*
6019 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
6021 return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
6024 /* Soft Debug support */
6025 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
6028 * mono_arch_set_breakpoint:
6030 * See mini-amd64.c for docs.
6032 void
6033 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
6035 guint8 *code = ip;
6036 guint32 addr = (guint32)bp_trigger_page;
6038 mips_load_const (code, mips_t9, addr);
6039 mips_lw (code, mips_t9, mips_t9, 0);
6041 mono_arch_flush_icache (ip, code - ip);
6045 * mono_arch_clear_breakpoint:
6047 * See mini-amd64.c for docs.
6049 void
6050 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
6052 guint8 *code = ip;
6054 mips_nop (code);
6055 mips_nop (code);
6056 mips_nop (code);
6058 mono_arch_flush_icache (ip, code - ip);
6062 * mono_arch_start_single_stepping:
6064 * See mini-amd64.c for docs.
6066 void
6067 mono_arch_start_single_stepping (void)
6069 mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
6073 * mono_arch_stop_single_stepping:
6075 * See mini-amd64.c for docs.
6077 void
6078 mono_arch_stop_single_stepping (void)
6080 mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
6084 * mono_arch_is_single_step_event:
6086 * See mini-amd64.c for docs.
6088 gboolean
6089 mono_arch_is_single_step_event (void *info, void *sigctx)
6091 siginfo_t* sinfo = (siginfo_t*) info;
6092 /* Sometimes the address is off by 4 */
6093 if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
6094 return TRUE;
6095 else
6096 return FALSE;
6100 * mono_arch_is_breakpoint_event:
6102 * See mini-amd64.c for docs.
6104 gboolean
6105 mono_arch_is_breakpoint_event (void *info, void *sigctx)
6107 siginfo_t* sinfo = (siginfo_t*) info;
6108 /* Sometimes the address is off by 4 */
6109 if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
6110 return TRUE;
6111 else
6112 return FALSE;
6116 * mono_arch_skip_breakpoint:
6118 * See mini-amd64.c for docs.
6120 void
6121 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
6123 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
6127 * mono_arch_skip_single_step:
6129 * See mini-amd64.c for docs.
6131 void
6132 mono_arch_skip_single_step (MonoContext *ctx)
6134 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
6138 * mono_arch_get_seq_point_info:
6140 * See mini-amd64.c for docs.
6142 gpointer
6143 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
6145 NOT_IMPLEMENTED;
6146 return NULL;
6149 #endif /* MONO_ARCH_SOFT_DEBUG_SUPPORTED */