[interp] Fix interp logging (#17636)
[mono-project.git] / mono / mini / mini-mips.c
blob6f6fdba6699ef38f22c62528efc9e6603b0754d0
1 /**
2 * \file
3 * MIPS backend for the Mono code generator
5 * Authors:
6 * Mark Mason (mason@broadcom.com)
8 * Based on mini-ppc.c by
9 * Paolo Molaro (lupus@ximian.com)
10 * Dietmar Maurer (dietmar@ximian.com)
12 * (C) 2006 Broadcom
13 * (C) 2003 Ximian, Inc.
15 #include "mini.h"
16 #include <string.h>
17 #include <asm/cachectl.h>
19 #include <mono/metadata/abi-details.h>
20 #include <mono/metadata/appdomain.h>
21 #include <mono/metadata/debug-helpers.h>
22 #include <mono/utils/mono-mmap.h>
23 #include <mono/utils/mono-hwcap.h>
24 #include <mono/utils/unlocked.h>
26 #include <mono/arch/mips/mips-codegen.h>
28 #include "mini-mips.h"
29 #include "cpu-mips.h"
30 #include "ir-emit.h"
31 #include "aot-runtime.h"
32 #include "mini-runtime.h"
33 #include "mono/utils/mono-tls-inline.h"
35 #define SAVE_FP_REGS 0
37 #define ALWAYS_SAVE_RA 1 /* call-handler & switch currently clobber ra */
39 #define PROMOTE_R4_TO_R8 1 /* promote single values in registers to doubles */
40 #define USE_MUL 0 /* use mul instead of mult/mflo for multiply
41 remember to update cpu-mips.md if you change this */
43 /* Emit a call sequence to 'v', using 'D' as a scratch register if necessary */
44 #define mips_call(c,D,v) do { \
45 guint32 _target = (guint32)(v); \
46 if (1 || ((v) == NULL) || ((_target & 0xfc000000) != (((guint32)(c)) & 0xfc000000))) { \
47 mips_load_const (c, D, _target); \
48 mips_jalr (c, D, mips_ra); \
49 } \
50 else { \
51 mips_jumpl (c, _target >> 2); \
52 } \
53 mips_nop (c); \
54 } while (0)
56 enum {
57 TLS_MODE_DETECT,
58 TLS_MODE_FAILED,
59 TLS_MODE_LTHREADS,
60 TLS_MODE_NPTL
63 /* This mutex protects architecture specific caches */
64 #define mono_mini_arch_lock() mono_os_mutex_lock (&mini_arch_mutex)
65 #define mono_mini_arch_unlock() mono_os_mutex_unlock (&mini_arch_mutex)
66 static mono_mutex_t mini_arch_mutex;
68 /* Whenever the host is little-endian */
69 static int little_endian;
70 /* Index of ms word/register */
71 static int ls_word_idx;
72 /* Index of ls word/register */
73 static int ms_word_idx;
74 /* Same for offsets */
75 static int ls_word_offset;
76 static int ms_word_offset;
79 * The code generated for sequence points reads from this location, which is
80 * made read-only when single stepping is enabled.
82 static gpointer ss_trigger_page;
84 /* Enabled breakpoints read from this trigger page */
85 static gpointer bp_trigger_page;
87 #undef DEBUG
88 #define DEBUG(a) if (cfg->verbose_level > 1) a
89 #undef DEBUG
90 #define DEBUG(a) a
91 #undef DEBUG
92 #define DEBUG(a)
94 #define EMIT_SYSTEM_EXCEPTION_NAME(exc_name) \
95 do { \
96 code = mips_emit_exc_by_name (code, exc_name); \
97 cfg->bb_exit->max_offset += 16; \
98 } while (0)
100 #define MONO_EMIT_NEW_LOAD_R8(cfg,dr,addr) do { \
101 MonoInst *inst; \
102 MONO_INST_NEW ((cfg), (inst), OP_R8CONST); \
103 inst->type = STACK_R8; \
104 inst->dreg = (dr); \
105 inst->inst_p0 = (void*)(addr); \
106 mono_bblock_add_inst (cfg->cbb, inst); \
107 } while (0)
109 #define ins_is_compare(ins) ((ins) && (((ins)->opcode == OP_COMPARE) \
110 || ((ins)->opcode == OP_ICOMPARE) \
111 || ((ins)->opcode == OP_LCOMPARE)))
112 #define ins_is_compare_imm(ins) ((ins) && (((ins)->opcode == OP_COMPARE_IMM) \
113 || ((ins)->opcode == OP_ICOMPARE_IMM) \
114 || ((ins)->opcode == OP_LCOMPARE_IMM)))
116 #define INS_REWRITE(ins, op, _s1, _s2) do { \
117 int s1 = _s1; \
118 int s2 = _s2; \
119 ins->opcode = (op); \
120 ins->sreg1 = (s1); \
121 ins->sreg2 = (s2); \
122 } while (0);
124 #define INS_REWRITE_IMM(ins, op, _s1, _imm) do { \
125 int s1 = _s1; \
126 ins->opcode = (op); \
127 ins->sreg1 = (s1); \
128 ins->inst_imm = (_imm); \
129 } while (0);
132 typedef struct InstList InstList;
134 struct InstList {
135 InstList *prev;
136 InstList *next;
137 MonoInst *data;
140 typedef enum {
141 ArgInIReg,
142 ArgOnStack,
143 ArgInFReg,
144 ArgStructByVal,
145 ArgStructByAddr
146 } ArgStorage;
148 typedef struct {
149 gint32 offset;
150 guint16 vtsize; /* in param area */
151 guint8 reg;
152 ArgStorage storage;
153 guint8 size : 4; /* 1, 2, 4, 8, or regs used by ArgStructByVal */
154 } ArgInfo;
156 struct CallInfo {
157 int nargs;
158 int gr;
159 int fr;
160 gboolean gr_passed;
161 gboolean on_stack;
162 gboolean vtype_retaddr;
163 int stack_size;
164 guint32 stack_usage;
165 guint32 struct_ret;
166 ArgInfo ret;
167 ArgInfo sig_cookie;
168 ArgInfo args [1];
171 void patch_lui_addiu(guint32 *ip, guint32 val);
172 static
173 guint8 *mono_arch_emit_epilog_sub (MonoCompile *cfg);
174 guint8 *mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins);
175 void mips_adjust_stackframe(MonoCompile *cfg);
176 void mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg);
177 MonoInst *mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args);
180 /* Not defined in asm/cachectl.h */
181 int cacheflush(char *addr, int nbytes, int cache);
183 void
184 mono_arch_flush_icache (guint8 *code, gint size)
186 /* Linux/MIPS specific */
187 cacheflush ((char*)code, size, BCACHE);
190 void
191 mono_arch_flush_register_windows (void)
195 gboolean
196 mono_arch_is_inst_imm (int opcode, int imm_opcode, gint64 imm)
198 return TRUE;
201 static guint8 *
202 mips_emit_exc_by_name(guint8 *code, const char *name)
204 gpointer addr;
205 MonoClass *exc_class;
207 exc_class = mono_class_load_from_name (mono_defaults.corlib, "System", name);
209 mips_load_const (code, mips_a0, m_class_get_type_token (exc_class));
210 addr = mono_get_throw_corlib_exception ();
211 mips_call (code, mips_t9, addr);
212 return code;
215 guint8 *
216 mips_emit_load_const (guint8 *code, int dreg, target_mgreg_t v)
218 if (mips_is_imm16 (v))
219 mips_addiu (code, dreg, mips_zero, ((guint32)v) & 0xffff);
220 else {
221 #if SIZEOF_REGISTER == 8
222 if (v != (long) v) {
223 /* v is not a sign-extended 32-bit value */
224 mips_lui (code, dreg, mips_zero, (guint32)((v >> (32+16)) & 0xffff));
225 mips_ori (code, dreg, dreg, (guint32)((v >> (32)) & 0xffff));
226 mips_dsll (code, dreg, dreg, 16);
227 mips_ori (code, dreg, dreg, (guint32)((v >> (16)) & 0xffff));
228 mips_dsll (code, dreg, dreg, 16);
229 mips_ori (code, dreg, dreg, (guint32)(v & 0xffff));
230 return code;
232 #endif
233 if (((guint32)v) & (1 << 15)) {
234 mips_lui (code, dreg, mips_zero, (((guint32)v)>>16)+1);
236 else {
237 mips_lui (code, dreg, mips_zero, (((guint32)v)>>16));
239 if (((guint32)v) & 0xffff)
240 mips_addiu (code, dreg, dreg, ((guint32)v) & 0xffff);
242 return code;
245 guint8 *
246 mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins)
248 g_assert (ins);
249 if (cfg->arch.long_branch) {
250 int br_offset = 5;
252 /* Invert test and emit branch around jump */
253 switch (op) {
254 case OP_MIPS_BEQ:
255 mips_bne (code, ins->sreg1, ins->sreg2, br_offset);
256 mips_nop (code);
257 break;
258 case OP_MIPS_BNE:
259 mips_beq (code, ins->sreg1, ins->sreg2, br_offset);
260 mips_nop (code);
261 break;
262 case OP_MIPS_BGEZ:
263 mips_bltz (code, ins->sreg1, br_offset);
264 mips_nop (code);
265 break;
266 case OP_MIPS_BGTZ:
267 mips_blez (code, ins->sreg1, br_offset);
268 mips_nop (code);
269 break;
270 case OP_MIPS_BLEZ:
271 mips_bgtz (code, ins->sreg1, br_offset);
272 mips_nop (code);
273 break;
274 case OP_MIPS_BLTZ:
275 mips_bgez (code, ins->sreg1, br_offset);
276 mips_nop (code);
277 break;
278 default:
279 g_assert_not_reached ();
281 mono_add_patch_info (cfg, code - cfg->native_code,
282 MONO_PATCH_INFO_BB, ins->inst_true_bb);
283 mips_lui (code, mips_at, mips_zero, 0);
284 mips_addiu (code, mips_at, mips_at, 0);
285 mips_jr (code, mips_at);
286 mips_nop (code);
288 else {
289 mono_add_patch_info (cfg, code - cfg->native_code,
290 MONO_PATCH_INFO_BB, ins->inst_true_bb);
291 switch (op) {
292 case OP_MIPS_BEQ:
293 mips_beq (code, ins->sreg1, ins->sreg2, 0);
294 mips_nop (code);
295 break;
296 case OP_MIPS_BNE:
297 mips_bne (code, ins->sreg1, ins->sreg2, 0);
298 mips_nop (code);
299 break;
300 case OP_MIPS_BGEZ:
301 mips_bgez (code, ins->sreg1, 0);
302 mips_nop (code);
303 break;
304 case OP_MIPS_BGTZ:
305 mips_bgtz (code, ins->sreg1, 0);
306 mips_nop (code);
307 break;
308 case OP_MIPS_BLEZ:
309 mips_blez (code, ins->sreg1, 0);
310 mips_nop (code);
311 break;
312 case OP_MIPS_BLTZ:
313 mips_bltz (code, ins->sreg1, 0);
314 mips_nop (code);
315 break;
316 default:
317 g_assert_not_reached ();
320 return (code);
323 /* XXX - big-endian dependent? */
324 void
325 patch_lui_addiu(guint32 *ip, guint32 val)
327 guint16 *__lui_addiu = (guint16*)(void *)(ip);
329 #if 0
330 printf ("patch_lui_addiu ip=0x%08x (0x%08x, 0x%08x) to point to 0x%08x\n",
331 ip, ((guint32 *)ip)[0], ((guint32 *)ip)[1], val);
332 fflush (stdout);
333 #endif
334 if (((guint32)(val)) & (1 << 15))
335 __lui_addiu [MINI_LS_WORD_IDX] = ((((guint32)(val)) >> 16) & 0xffff) + 1;
336 else
337 __lui_addiu [MINI_LS_WORD_IDX] = (((guint32)(val)) >> 16) & 0xffff;
338 __lui_addiu [MINI_LS_WORD_IDX + 2] = ((guint32)(val)) & 0xffff;
339 mono_arch_flush_icache ((guint8 *)ip, 8);
342 guint32 trap_target;
343 void
344 mips_patch (guint32 *code, guint32 target)
346 guint32 ins = *code;
347 guint32 op = ins >> 26;
348 guint32 diff, offset;
350 g_assert (trap_target != target);
351 //printf ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
352 switch (op) {
353 case 0x00: /* jr ra */
354 if (ins == 0x3e00008)
355 break;
356 g_assert_not_reached ();
357 break;
358 case 0x02: /* j */
359 case 0x03: /* jal */
360 g_assert (!(target & 0x03));
361 g_assert ((target & 0xfc000000) == (((guint32)code) & 0xfc000000));
362 ins = (ins & 0xfc000000) | (((target) >> 2) & 0x03ffffff);
363 *code = ins;
364 mono_arch_flush_icache ((guint8 *)code, 4);
365 break;
366 case 0x01: /* BLTZ */
367 case 0x04: /* BEQ */
368 case 0x05: /* BNE */
369 case 0x06: /* BLEZ */
370 case 0x07: /* BGTZ */
371 case 0x11: /* bc1t */
372 diff = target - (guint32)(code + 1);
373 g_assert (((diff & 0x0003ffff) == diff) || ((diff | 0xfffc0000) == diff));
374 g_assert (!(diff & 0x03));
375 offset = ((gint32)diff) >> 2;
376 if (((int)offset) != ((int)(short)offset))
377 g_assert (((int)offset) == ((int)(short)offset));
378 ins = (ins & 0xffff0000) | (offset & 0x0000ffff);
379 *code = ins;
380 mono_arch_flush_icache ((guint8 *)code, 4);
381 break;
382 case 0x0f: /* LUI / ADDIU pair */
383 g_assert ((code[1] >> 26) == 0x9);
384 patch_lui_addiu (code, target);
385 mono_arch_flush_icache ((guint8 *)code, 8);
386 break;
388 default:
389 printf ("unknown op 0x%02x (0x%08x) @ %p\n", op, ins, code);
390 g_assert_not_reached ();
394 static void mono_arch_compute_omit_fp (MonoCompile *cfg);
396 const char*
397 mono_arch_regname (int reg) {
398 #if _MIPS_SIM == _ABIO32
399 static const char * rnames[] = {
400 "zero", "at", "v0", "v1",
401 "a0", "a1", "a2", "a3",
402 "t0", "t1", "t2", "t3",
403 "t4", "t5", "t6", "t7",
404 "s0", "s1", "s2", "s3",
405 "s4", "s5", "s6", "s7",
406 "t8", "t9", "k0", "k1",
407 "gp", "sp", "fp", "ra"
409 #elif _MIPS_SIM == _ABIN32
410 static const char * rnames[] = {
411 "zero", "at", "v0", "v1",
412 "a0", "a1", "a2", "a3",
413 "a4", "a5", "a6", "a7",
414 "t0", "t1", "t2", "t3",
415 "s0", "s1", "s2", "s3",
416 "s4", "s5", "s6", "s7",
417 "t8", "t9", "k0", "k1",
418 "gp", "sp", "fp", "ra"
420 #endif
421 if (reg >= 0 && reg < 32)
422 return rnames [reg];
423 return "unknown";
426 const char*
427 mono_arch_fregname (int reg) {
428 static const char * rnames[] = {
429 "f0", "f1", "f2", "f3",
430 "f4", "f5", "f6", "f7",
431 "f8", "f9", "f10", "f11",
432 "f12", "f13", "f14", "f15",
433 "f16", "f17", "f18", "f19",
434 "f20", "f21", "f22", "f23",
435 "f24", "f25", "f26", "f27",
436 "f28", "f29", "f30", "f31"
438 if (reg >= 0 && reg < 32)
439 return rnames [reg];
440 return "unknown";
443 /* this function overwrites at */
444 static guint8*
445 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
447 /* XXX write a loop, not an unrolled loop */
448 while (size > 0) {
449 mips_lw (code, mips_at, sreg, soffset);
450 mips_sw (code, mips_at, dreg, doffset);
451 size -= 4;
452 soffset += 4;
453 doffset += 4;
455 return code;
459 * mono_arch_get_argument_info:
460 * @csig: a method signature
461 * @param_count: the number of parameters to consider
462 * @arg_info: an array to store the result infos
464 * Gathers information on parameters such as size, alignment and
465 * padding. arg_info should be large enought to hold param_count + 1 entries.
467 * Returns the size of the activation frame.
470 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
472 int k, frame_size = 0;
473 guint32 size, align, pad;
474 int offset = 0;
476 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
477 frame_size += sizeof (target_mgreg_t);
478 offset += 4;
481 arg_info [0].offset = offset;
483 if (csig->hasthis) {
484 frame_size += sizeof (target_mgreg_t);
485 offset += 4;
488 arg_info [0].size = frame_size;
490 for (k = 0; k < param_count; k++) {
491 size = mini_type_stack_size_full (csig->params [k], &align, csig->pinvoke);
493 /* ignore alignment for now */
494 align = 1;
496 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
497 arg_info [k].pad = pad;
498 frame_size += size;
499 arg_info [k + 1].pad = 0;
500 arg_info [k + 1].size = size;
501 offset += pad;
502 arg_info [k + 1].offset = offset;
503 offset += size;
506 align = MONO_ARCH_FRAME_ALIGNMENT;
507 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
508 arg_info [k].pad = pad;
510 return frame_size;
513 /* The delegate object plus 3 params */
514 #define MAX_ARCH_DELEGATE_PARAMS (4 - 1)
516 static guint8*
517 get_delegate_invoke_impl (MonoTrampInfo **info, gboolean has_target, gboolean param_count)
519 guint8 *code, *start;
521 if (has_target) {
522 start = code = mono_global_codeman_reserve (16);
524 /* Replace the this argument with the target */
525 mips_lw (code, mips_temp, mips_a0, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
526 mips_lw (code, mips_a0, mips_a0, MONO_STRUCT_OFFSET (MonoDelegate, target));
527 mips_jr (code, mips_temp);
528 mips_nop (code);
530 g_assert ((code - start) <= 16);
532 mono_arch_flush_icache (start, 16);
533 MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_DELEGATE_INVOKE, NULL));
534 } else {
535 int size, i;
537 size = 16 + param_count * 4;
538 start = code = mono_global_codeman_reserve (size);
540 mips_lw (code, mips_temp, mips_a0, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
541 /* slide down the arguments */
542 for (i = 0; i < param_count; ++i) {
543 mips_move (code, mips_a0 + i, mips_a0 + i + 1);
545 mips_jr (code, mips_temp);
546 mips_nop (code);
548 g_assert ((code - start) <= size);
550 mono_arch_flush_icache (start, size);
551 MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_DELEGATE_INVOKE, NULL));
554 if (has_target) {
555 *info = mono_tramp_info_create ("delegate_invoke_impl_has_target", start, code - start, NULL, NULL);
556 } else {
557 char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", param_count);
558 *info = mono_tramp_info_create (name, start, code - start, NULL, NULL);
559 g_free (name);
562 return start;
566 * mono_arch_get_delegate_invoke_impls:
568 * Return a list of MonoAotTrampInfo structures for the delegate invoke impl
569 * trampolines.
571 GSList*
572 mono_arch_get_delegate_invoke_impls (void)
574 GSList *res = NULL;
575 MonoTrampInfo *info;
576 int i;
578 get_delegate_invoke_impl (&info, TRUE, 0);
579 res = g_slist_prepend (res, info);
581 for (i = 0; i <= MAX_ARCH_DELEGATE_PARAMS; ++i) {
582 get_delegate_invoke_impl (&info, FALSE, i);
583 res = g_slist_prepend (res, info);
586 return res;
589 gpointer
590 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
592 guint8 *code, *start;
594 /* FIXME: Support more cases */
595 if (MONO_TYPE_ISSTRUCT (sig->ret))
596 return NULL;
598 if (has_target) {
599 static guint8* cached = NULL;
600 mono_mini_arch_lock ();
601 if (cached) {
602 mono_mini_arch_unlock ();
603 return cached;
606 if (mono_ee_features.use_aot_trampolines) {
607 start = mono_aot_get_trampoline ("delegate_invoke_impl_has_target");
608 } else {
609 MonoTrampInfo *info;
610 start = get_delegate_invoke_impl (&info, TRUE, 0);
611 mono_tramp_info_register (info, NULL);
613 cached = start;
614 mono_mini_arch_unlock ();
615 return cached;
616 } else {
617 static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
618 int i;
620 if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
621 return NULL;
622 for (i = 0; i < sig->param_count; ++i)
623 if (!mono_is_regsize_var (sig->params [i]))
624 return NULL;
626 mono_mini_arch_lock ();
627 code = cache [sig->param_count];
628 if (code) {
629 mono_mini_arch_unlock ();
630 return code;
633 if (mono_ee_features.use_aot_trampolines) {
634 char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", sig->param_count);
635 start = mono_aot_get_trampoline (name);
636 g_free (name);
637 } else {
638 MonoTrampInfo *info;
639 start = get_delegate_invoke_impl (&info, FALSE, sig->param_count);
640 mono_tramp_info_register (info, NULL);
642 cache [sig->param_count] = start;
643 mono_mini_arch_unlock ();
644 return start;
647 return NULL;
650 gpointer
651 mono_arch_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method, int offset, gboolean load_imt_reg)
653 return NULL;
656 gpointer
657 mono_arch_get_this_arg_from_call (host_mgreg_t *regs, guint8 *code)
659 g_assert(regs);
660 return (gpointer)regs [mips_a0];
664 * Initialize the cpu to execute managed code.
666 void
667 mono_arch_cpu_init (void)
669 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
670 little_endian = 1;
671 ls_word_idx = 0;
672 ms_word_idx = 1;
673 #else
674 ls_word_idx = 1;
675 ms_word_idx = 0;
676 #endif
678 ls_word_offset = ls_word_idx * 4;
679 ms_word_offset = ms_word_idx * 4;
683 * Initialize architecture specific code.
685 void
686 mono_arch_init (void)
688 mono_os_mutex_init_recursive (&mini_arch_mutex);
690 ss_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ, MONO_MEM_ACCOUNT_OTHER);
691 bp_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ, MONO_MEM_ACCOUNT_OTHER);
692 mono_mprotect (bp_trigger_page, mono_pagesize (), 0);
696 * Cleanup architecture specific code.
698 void
699 mono_arch_cleanup (void)
701 mono_os_mutex_destroy (&mini_arch_mutex);
704 gboolean
705 mono_arch_have_fast_tls (void)
707 return FALSE;
711 * This function returns the optimizations supported on this cpu.
713 guint32
714 mono_arch_cpu_optimizations (guint32 *exclude_mask)
716 guint32 opts = 0;
718 /* no mips-specific optimizations yet */
719 *exclude_mask = 0;
720 return opts;
724 * This function test for all SIMD functions supported.
726 * Returns a bitmask corresponding to all supported versions.
729 guint32
730 mono_arch_cpu_enumerate_simd_versions (void)
732 /* SIMD is currently unimplemented */
733 return 0;
736 GList *
737 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
739 GList *vars = NULL;
740 int i;
742 for (i = 0; i < cfg->num_varinfo; i++) {
743 MonoInst *ins = cfg->varinfo [i];
744 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
746 /* unused vars */
747 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
748 continue;
750 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
751 continue;
753 /* we can only allocate 32 bit values */
754 if (mono_is_regsize_var (ins->inst_vtype)) {
755 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
756 g_assert (i == vmv->idx);
757 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
761 return vars;
764 GList *
765 mono_arch_get_global_int_regs (MonoCompile *cfg)
767 GList *regs = NULL;
769 regs = g_list_prepend (regs, (gpointer)mips_s0);
770 regs = g_list_prepend (regs, (gpointer)mips_s1);
771 regs = g_list_prepend (regs, (gpointer)mips_s2);
772 regs = g_list_prepend (regs, (gpointer)mips_s3);
773 regs = g_list_prepend (regs, (gpointer)mips_s4);
774 //regs = g_list_prepend (regs, (gpointer)mips_s5);
775 regs = g_list_prepend (regs, (gpointer)mips_s6);
776 regs = g_list_prepend (regs, (gpointer)mips_s7);
778 return regs;
782 * mono_arch_regalloc_cost:
784 * Return the cost, in number of memory references, of the action of
785 * allocating the variable VMV into a register during global register
786 * allocation.
788 guint32
789 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
791 /* FIXME: */
792 return 2;
795 static void
796 args_onto_stack (CallInfo *info)
798 g_assert (!info->on_stack);
799 g_assert (info->stack_size <= MIPS_STACK_PARAM_OFFSET);
800 info->on_stack = TRUE;
801 info->stack_size = MIPS_STACK_PARAM_OFFSET;
804 #if _MIPS_SIM == _ABIO32
806 * O32 calling convention version
809 static void
810 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
811 /* First, see if we need to drop onto the stack */
812 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
813 args_onto_stack (info);
815 /* Now, place the argument */
816 if (info->on_stack) {
817 ainfo->storage = ArgOnStack;
818 ainfo->reg = mips_sp; /* in the caller */
819 ainfo->offset = info->stack_size;
821 else {
822 ainfo->storage = ArgInIReg;
823 ainfo->reg = info->gr;
824 info->gr += 1;
825 info->gr_passed = TRUE;
827 info->stack_size += 4;
830 static void
831 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
832 /* First, see if we need to drop onto the stack */
833 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
834 args_onto_stack (info);
836 /* Now, place the argument */
837 if (info->on_stack) {
838 g_assert (info->stack_size % 4 == 0);
839 info->stack_size += (info->stack_size % 8);
841 ainfo->storage = ArgOnStack;
842 ainfo->reg = mips_sp; /* in the caller */
843 ainfo->offset = info->stack_size;
845 else {
846 // info->gr must be a0 or a2
847 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
848 g_assert(info->gr <= MIPS_LAST_ARG_REG);
850 ainfo->storage = ArgInIReg;
851 ainfo->reg = info->gr;
852 info->gr += 2;
853 info->gr_passed = TRUE;
855 info->stack_size += 8;
858 static void
859 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
860 /* First, see if we need to drop onto the stack */
861 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
862 args_onto_stack (info);
864 /* Now, place the argument */
865 if (info->on_stack) {
866 ainfo->storage = ArgOnStack;
867 ainfo->reg = mips_sp; /* in the caller */
868 ainfo->offset = info->stack_size;
870 else {
871 /* Only use FP regs for args if no int args passed yet */
872 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
873 ainfo->storage = ArgInFReg;
874 ainfo->reg = info->fr;
875 /* Even though it's a single-precision float, it takes up two FP regs */
876 info->fr += 2;
877 /* FP and GP slots do not overlap */
878 info->gr += 1;
880 else {
881 /* Passing single-precision float arg in a GP register
882 * such as: func (0, 1.0, 2, 3);
883 * In this case, only one 'gr' register is consumed.
885 ainfo->storage = ArgInIReg;
886 ainfo->reg = info->gr;
888 info->gr += 1;
889 info->gr_passed = TRUE;
892 info->stack_size += 4;
895 static void
896 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
897 /* First, see if we need to drop onto the stack */
898 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
899 args_onto_stack (info);
901 /* Now, place the argument */
902 if (info->on_stack) {
903 g_assert(info->stack_size % 4 == 0);
904 info->stack_size += (info->stack_size % 8);
906 ainfo->storage = ArgOnStack;
907 ainfo->reg = mips_sp; /* in the caller */
908 ainfo->offset = info->stack_size;
910 else {
911 /* Only use FP regs for args if no int args passed yet */
912 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
913 ainfo->storage = ArgInFReg;
914 ainfo->reg = info->fr;
915 info->fr += 2;
916 /* FP and GP slots do not overlap */
917 info->gr += 2;
919 else {
920 // info->gr must be a0 or a2
921 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
922 g_assert(info->gr <= MIPS_LAST_ARG_REG);
924 ainfo->storage = ArgInIReg;
925 ainfo->reg = info->gr;
926 info->gr += 2;
927 info->gr_passed = TRUE;
930 info->stack_size += 8;
932 #elif _MIPS_SIM == _ABIN32
934 * N32 calling convention version
937 static void
938 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
939 /* First, see if we need to drop onto the stack */
940 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
941 args_onto_stack (info);
943 /* Now, place the argument */
944 if (info->on_stack) {
945 ainfo->storage = ArgOnStack;
946 ainfo->reg = mips_sp; /* in the caller */
947 ainfo->offset = info->stack_size;
948 info->stack_size += SIZEOF_REGISTER;
950 else {
951 ainfo->storage = ArgInIReg;
952 ainfo->reg = info->gr;
953 info->gr += 1;
954 info->gr_passed = TRUE;
958 static void
959 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
960 /* First, see if we need to drop onto the stack */
961 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
962 args_onto_stack (info);
964 /* Now, place the argument */
965 if (info->on_stack) {
966 g_assert (info->stack_size % 4 == 0);
967 info->stack_size += (info->stack_size % 8);
969 ainfo->storage = ArgOnStack;
970 ainfo->reg = mips_sp; /* in the caller */
971 ainfo->offset = info->stack_size;
972 info->stack_size += SIZEOF_REGISTER;
974 else {
975 g_assert (info->gr <= MIPS_LAST_ARG_REG);
977 ainfo->storage = ArgInIReg;
978 ainfo->reg = info->gr;
979 info->gr += 1;
980 info->gr_passed = TRUE;
984 static void
985 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
986 /* First, see if we need to drop onto the stack */
987 if (!info->on_stack) {
988 if (info->gr > MIPS_LAST_ARG_REG)
989 args_onto_stack (info);
990 else if (info->fr > MIPS_LAST_FPARG_REG)
991 args_onto_stack (info);
994 /* Now, place the argument */
995 if (info->on_stack) {
996 ainfo->storage = ArgOnStack;
997 ainfo->reg = mips_sp; /* in the caller */
998 ainfo->offset = info->stack_size;
999 info->stack_size += FREG_SIZE;
1001 else {
1002 ainfo->storage = ArgInFReg;
1003 ainfo->reg = info->fr;
1004 info->fr += 1;
1005 /* FP and GP slots do not overlap */
1006 info->gr += 1;
1010 static void
1011 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
1012 /* First, see if we need to drop onto the stack */
1013 if (!info->on_stack) {
1014 if (info->gr > MIPS_LAST_ARG_REG)
1015 args_onto_stack (info);
1016 else if (info->fr > MIPS_LAST_FPARG_REG)
1017 args_onto_stack (info);
1020 /* Now, place the argument */
1021 if (info->on_stack) {
1022 g_assert(info->stack_size % 4 == 0);
1023 info->stack_size += (info->stack_size % 8);
1025 ainfo->storage = ArgOnStack;
1026 ainfo->reg = mips_sp; /* in the caller */
1027 ainfo->offset = info->stack_size;
1028 info->stack_size += FREG_SIZE;
1030 else {
1031 ainfo->storage = ArgInFReg;
1032 ainfo->reg = info->fr;
1033 info->fr += 1;
1034 /* FP and GP slots do not overlap */
1035 info->gr += 1;
1038 #endif
1040 static CallInfo*
1041 get_call_info (MonoMemPool *mp, MonoMethodSignature *sig)
1043 guint i;
1044 int n = sig->hasthis + sig->param_count;
1045 int pstart;
1046 MonoType* simpletype;
1047 CallInfo *cinfo;
1048 gboolean is_pinvoke = sig->pinvoke;
1050 if (mp)
1051 cinfo = mono_mempool_alloc0 (mp, sizeof (CallInfo) + (sizeof (ArgInfo) * n));
1052 else
1053 cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
1055 cinfo->fr = MIPS_FIRST_FPARG_REG;
1056 cinfo->gr = MIPS_FIRST_ARG_REG;
1057 cinfo->stack_size = 0;
1059 DEBUG(printf("calculate_sizes\n"));
1061 cinfo->vtype_retaddr = MONO_TYPE_ISSTRUCT (sig->ret) ? TRUE : FALSE;
1062 pstart = 0;
1063 n = 0;
1064 #if 0
1065 /* handle returning a struct */
1066 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1067 cinfo->struct_ret = cinfo->gr;
1068 add_int32_arg (cinfo, &cinfo->ret);
1071 if (sig->hasthis) {
1072 add_int32_arg (cinfo, cinfo->args + n);
1073 n++;
1075 #else
1077 * To simplify get_this_arg_reg () and LLVM integration, emit the vret arg after
1078 * the first argument, allowing 'this' to be always passed in the first arg reg.
1079 * Also do this if the first argument is a reference type, since virtual calls
1080 * are sometimes made using calli without sig->hasthis set, like in the delegate
1081 * invoke wrappers.
1083 if (cinfo->vtype_retaddr && !is_pinvoke && (sig->hasthis || (sig->param_count > 0 && MONO_TYPE_IS_REFERENCE (mini_get_underlying_type (sig->params [0]))))) {
1084 if (sig->hasthis) {
1085 add_int32_arg (cinfo, cinfo->args + n);
1086 n ++;
1087 } else {
1088 add_int32_arg (cinfo, cinfo->args + sig->hasthis);
1089 pstart = 1;
1090 n ++;
1092 add_int32_arg (cinfo, &cinfo->ret);
1093 cinfo->struct_ret = cinfo->ret.reg;
1094 } else {
1095 /* this */
1096 if (sig->hasthis) {
1097 add_int32_arg (cinfo, cinfo->args + n);
1098 n ++;
1101 if (cinfo->vtype_retaddr) {
1102 add_int32_arg (cinfo, &cinfo->ret);
1103 cinfo->struct_ret = cinfo->ret.reg;
1106 #endif
1108 DEBUG(printf("params: %d\n", sig->param_count));
1109 for (i = pstart; i < sig->param_count; ++i) {
1110 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1111 /* Prevent implicit arguments and sig_cookie from
1112 being passed in registers */
1113 args_onto_stack (cinfo);
1114 /* Emit the signature cookie just before the implicit arguments */
1115 add_int32_arg (cinfo, &cinfo->sig_cookie);
1117 DEBUG(printf("param %d: ", i));
1118 simpletype = mini_get_underlying_type (sig->params [i]);
1119 switch (simpletype->type) {
1120 case MONO_TYPE_I1:
1121 case MONO_TYPE_U1:
1122 DEBUG(printf("1 byte\n"));
1123 cinfo->args [n].size = 1;
1124 add_int32_arg (cinfo, &cinfo->args[n]);
1125 n++;
1126 break;
1127 case MONO_TYPE_I2:
1128 case MONO_TYPE_U2:
1129 DEBUG(printf("2 bytes\n"));
1130 cinfo->args [n].size = 2;
1131 add_int32_arg (cinfo, &cinfo->args[n]);
1132 n++;
1133 break;
1134 case MONO_TYPE_I4:
1135 case MONO_TYPE_U4:
1136 DEBUG(printf("4 bytes\n"));
1137 cinfo->args [n].size = 4;
1138 add_int32_arg (cinfo, &cinfo->args[n]);
1139 n++;
1140 break;
1141 case MONO_TYPE_I:
1142 case MONO_TYPE_U:
1143 case MONO_TYPE_PTR:
1144 case MONO_TYPE_FNPTR:
1145 case MONO_TYPE_OBJECT:
1146 cinfo->args [n].size = sizeof (target_mgreg_t);
1147 add_int32_arg (cinfo, &cinfo->args[n]);
1148 n++;
1149 break;
1150 case MONO_TYPE_GENERICINST:
1151 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1152 cinfo->args [n].size = sizeof (target_mgreg_t);
1153 add_int32_arg (cinfo, &cinfo->args[n]);
1154 n++;
1155 break;
1157 /* Fall through */
1158 case MONO_TYPE_TYPEDBYREF:
1159 case MONO_TYPE_VALUETYPE: {
1160 int j;
1161 int nwords = 0;
1162 int has_offset = FALSE;
1163 ArgInfo dummy_arg;
1164 gint size, alignment;
1165 MonoClass *klass;
1167 if (simpletype->type == MONO_TYPE_TYPEDBYREF) {
1168 size = MONO_ABI_SIZEOF (MonoTypedRef);
1169 alignment = sizeof (target_mgreg_t);
1170 } else {
1171 klass = mono_class_from_mono_type_internal (sig->params [i]);
1172 if (is_pinvoke)
1173 size = mono_class_native_size (klass, NULL);
1174 else
1175 size = mono_class_value_size (klass, NULL);
1176 alignment = mono_class_min_align (klass);
1178 #if MIPS_PASS_STRUCTS_BY_VALUE
1179 /* Need to do alignment if struct contains long or double */
1180 if (alignment > 4) {
1181 /* Drop onto stack *before* looking at
1182 stack_size, if required. */
1183 if (!cinfo->on_stack && cinfo->gr > MIPS_LAST_ARG_REG)
1184 args_onto_stack (cinfo);
1185 if (cinfo->stack_size & (alignment - 1)) {
1186 add_int32_arg (cinfo, &dummy_arg);
1188 g_assert (!(cinfo->stack_size & (alignment - 1)));
1191 #if 0
1192 g_printf ("valuetype struct size=%d offset=%d align=%d\n",
1193 mono_class_native_size (sig->params [i]->data.klass, NULL),
1194 cinfo->stack_size, alignment);
1195 #endif
1196 nwords = (size + sizeof (target_mgreg_t) -1 ) / sizeof (target_mgreg_t);
1197 g_assert (cinfo->args [n].size == 0);
1198 g_assert (cinfo->args [n].vtsize == 0);
1199 for (j = 0; j < nwords; ++j) {
1200 if (j == 0) {
1201 add_int32_arg (cinfo, &cinfo->args [n]);
1202 if (cinfo->on_stack)
1203 has_offset = TRUE;
1204 } else {
1205 add_int32_arg (cinfo, &dummy_arg);
1206 if (!has_offset && cinfo->on_stack) {
1207 cinfo->args [n].offset = dummy_arg.offset;
1208 has_offset = TRUE;
1211 if (cinfo->on_stack)
1212 cinfo->args [n].vtsize += 1;
1213 else
1214 cinfo->args [n].size += 1;
1216 //g_printf ("\tstack_size=%d vtsize=%d\n", cinfo->args [n].size, cinfo->args[n].vtsize);
1217 cinfo->args [n].storage = ArgStructByVal;
1218 #else
1219 add_int32_arg (cinfo, &cinfo->args[n]);
1220 cinfo->args [n].storage = ArgStructByAddr;
1221 #endif
1222 n++;
1223 break;
1225 case MONO_TYPE_U8:
1226 case MONO_TYPE_I8:
1227 DEBUG(printf("8 bytes\n"));
1228 cinfo->args [n].size = 8;
1229 add_int64_arg (cinfo, &cinfo->args[n]);
1230 n++;
1231 break;
1232 case MONO_TYPE_R4:
1233 DEBUG(printf("R4\n"));
1234 cinfo->args [n].size = 4;
1235 add_float32_arg (cinfo, &cinfo->args[n]);
1236 n++;
1237 break;
1238 case MONO_TYPE_R8:
1239 DEBUG(printf("R8\n"));
1240 cinfo->args [n].size = 8;
1241 add_float64_arg (cinfo, &cinfo->args[n]);
1242 n++;
1243 break;
1244 default:
1245 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
1249 /* Handle the case where there are no implicit arguments */
1250 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1251 /* Prevent implicit arguments and sig_cookie from
1252 being passed in registers */
1253 args_onto_stack (cinfo);
1254 /* Emit the signature cookie just before the implicit arguments */
1255 add_int32_arg (cinfo, &cinfo->sig_cookie);
1259 simpletype = mini_get_underlying_type (sig->ret);
1260 switch (simpletype->type) {
1261 case MONO_TYPE_I1:
1262 case MONO_TYPE_U1:
1263 case MONO_TYPE_I2:
1264 case MONO_TYPE_U2:
1265 case MONO_TYPE_I4:
1266 case MONO_TYPE_U4:
1267 case MONO_TYPE_I:
1268 case MONO_TYPE_U:
1269 case MONO_TYPE_PTR:
1270 case MONO_TYPE_FNPTR:
1271 case MONO_TYPE_OBJECT:
1272 cinfo->ret.reg = mips_v0;
1273 break;
1274 case MONO_TYPE_U8:
1275 case MONO_TYPE_I8:
1276 cinfo->ret.reg = mips_v0;
1277 break;
1278 case MONO_TYPE_R4:
1279 case MONO_TYPE_R8:
1280 cinfo->ret.reg = mips_f0;
1281 cinfo->ret.storage = ArgInFReg;
1282 break;
1283 case MONO_TYPE_GENERICINST:
1284 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1285 cinfo->ret.reg = mips_v0;
1286 break;
1288 break;
1289 case MONO_TYPE_VALUETYPE:
1290 case MONO_TYPE_TYPEDBYREF:
1291 break;
1292 case MONO_TYPE_VOID:
1293 break;
1294 default:
1295 g_error ("Can't handle as return value 0x%x", sig->ret->type);
1299 /* align stack size to 16 */
1300 cinfo->stack_size = (cinfo->stack_size + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1302 cinfo->stack_usage = cinfo->stack_size;
1303 return cinfo;
1306 static gboolean
1307 debug_omit_fp (void)
1309 #if 0
1310 return mono_debug_count ();
1311 #else
1312 return TRUE;
1313 #endif
1317 * mono_arch_compute_omit_fp:
1318 * Determine whether the frame pointer can be eliminated.
1320 static void
1321 mono_arch_compute_omit_fp (MonoCompile *cfg)
1323 MonoMethodSignature *sig;
1324 MonoMethodHeader *header;
1325 int i, locals_size;
1326 CallInfo *cinfo;
1328 if (cfg->arch.omit_fp_computed)
1329 return;
1331 header = cfg->header;
1333 sig = mono_method_signature_internal (cfg->method);
1335 if (!cfg->arch.cinfo)
1336 cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
1337 cinfo = cfg->arch.cinfo;
1340 * FIXME: Remove some of the restrictions.
1342 cfg->arch.omit_fp = TRUE;
1343 cfg->arch.omit_fp_computed = TRUE;
1345 if (cfg->disable_omit_fp)
1346 cfg->arch.omit_fp = FALSE;
1347 if (!debug_omit_fp ())
1348 cfg->arch.omit_fp = FALSE;
1349 if (cfg->method->save_lmf)
1350 cfg->arch.omit_fp = FALSE;
1351 if (cfg->flags & MONO_CFG_HAS_ALLOCA)
1352 cfg->arch.omit_fp = FALSE;
1353 if (header->num_clauses)
1354 cfg->arch.omit_fp = FALSE;
1355 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
1356 cfg->arch.omit_fp = FALSE;
1358 * On MIPS, fp points to the bottom of the frame, so it can be eliminated even if
1359 * there are stack arguments.
1362 if (cinfo->stack_usage)
1363 cfg->arch.omit_fp = FALSE;
1366 locals_size = 0;
1367 for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
1368 MonoInst *ins = cfg->varinfo [i];
1369 int ialign;
1371 locals_size += mono_type_size (ins->inst_vtype, &ialign);
1374 //printf ("D: %s %d\n", cfg->method->name, cfg->arch.omit_fp);
1378 * Set var information according to the calling convention. mips version.
1379 * The locals var stuff should most likely be split in another method.
1381 void
1382 mono_arch_allocate_vars (MonoCompile *cfg)
1384 MonoMethodSignature *sig;
1385 MonoMethodHeader *header;
1386 MonoInst *inst;
1387 int i, offset, size, align, curinst;
1388 int frame_reg = mips_sp;
1389 guint32 iregs_to_save = 0;
1390 #if SAVE_FP_REGS
1391 guint32 fregs_to_restore;
1392 #endif
1393 CallInfo *cinfo;
1395 sig = mono_method_signature_internal (cfg->method);
1397 if (!cfg->arch.cinfo)
1398 cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
1399 cinfo = cfg->arch.cinfo;
1401 mono_arch_compute_omit_fp (cfg);
1403 /* spill down, we'll fix it in a separate pass */
1404 // cfg->flags |= MONO_CFG_HAS_SPILLUP;
1406 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1407 * call convs needs to be handled this way.
1409 if (cfg->flags & MONO_CFG_HAS_VARARGS)
1410 cfg->param_area = MAX (cfg->param_area, sizeof (target_mgreg_t)*8);
1412 /* gtk-sharp and other broken code will dllimport vararg functions even with
1413 * non-varargs signatures. Since there is little hope people will get this right
1414 * we assume they won't.
1416 if (cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1417 cfg->param_area = MAX (cfg->param_area, sizeof (target_mgreg_t)*8);
1419 /* a0-a3 always present */
1420 cfg->param_area = MAX (cfg->param_area, MIPS_STACK_PARAM_OFFSET);
1422 header = cfg->header;
1424 if (cfg->arch.omit_fp)
1425 frame_reg = mips_sp;
1426 else
1427 frame_reg = mips_fp;
1428 cfg->frame_reg = frame_reg;
1429 if (frame_reg != mips_sp) {
1430 cfg->used_int_regs |= 1 << frame_reg;
1433 offset = 0;
1434 curinst = 0;
1435 if (!MONO_TYPE_ISSTRUCT (sig->ret)) {
1436 /* FIXME: handle long and FP values */
1437 switch (mini_get_underlying_type (sig->ret)->type) {
1438 case MONO_TYPE_VOID:
1439 break;
1440 case MONO_TYPE_R4:
1441 case MONO_TYPE_R8:
1442 cfg->ret->opcode = OP_REGVAR;
1443 cfg->ret->inst_c0 = cfg->ret->dreg = mips_f0;
1444 break;
1445 default:
1446 cfg->ret->opcode = OP_REGVAR;
1447 cfg->ret->inst_c0 = mips_v0;
1448 break;
1451 /* Space for outgoing parameters, including a0-a3 */
1452 offset += cfg->param_area;
1454 /* Now handle the local variables */
1456 curinst = cfg->locals_start;
1457 for (i = curinst; i < cfg->num_varinfo; ++i) {
1458 inst = cfg->varinfo [i];
1459 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
1460 continue;
1462 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
1463 * pinvoke wrappers when they call functions returning structure
1465 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
1466 size = mono_class_native_size (mono_class_from_mono_type_internal (inst->inst_vtype), (unsigned int *) &align);
1467 else
1468 size = mono_type_size (inst->inst_vtype, &align);
1470 offset += align - 1;
1471 offset &= ~(align - 1);
1472 inst->inst_offset = offset;
1473 inst->opcode = OP_REGOFFSET;
1474 inst->inst_basereg = frame_reg;
1475 offset += size;
1476 // g_print ("allocating local %d to %d\n", i, inst->inst_offset);
1479 /* Space for LMF (if needed) */
1480 if (cfg->method->save_lmf) {
1481 /* align the offset to 16 bytes */
1482 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1483 cfg->arch.lmf_offset = offset;
1484 offset += sizeof (MonoLMF);
1487 if (sig->call_convention == MONO_CALL_VARARG) {
1488 size = 4;
1489 align = 4;
1491 /* Allocate a local slot to hold the sig cookie address */
1492 offset += align - 1;
1493 offset &= ~(align - 1);
1494 cfg->sig_cookie = offset;
1495 offset += size;
1498 offset += SIZEOF_REGISTER - 1;
1499 offset &= ~(SIZEOF_REGISTER - 1);
1501 /* Space for saved registers */
1502 cfg->arch.iregs_offset = offset;
1503 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
1504 if (iregs_to_save) {
1505 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
1506 if (iregs_to_save & (1 << i)) {
1507 offset += SIZEOF_REGISTER;
1512 /* saved float registers */
1513 #if SAVE_FP_REGS
1514 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
1515 if (fregs_to_restore) {
1516 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
1517 if (fregs_to_restore & (1 << i)) {
1518 offset += sizeof(double);
1522 #endif
1524 #if _MIPS_SIM == _ABIO32
1525 /* Now add space for saving the ra */
1526 offset += TARGET_SIZEOF_VOID_P;
1528 /* change sign? */
1529 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1530 cfg->stack_offset = offset;
1531 cfg->arch.local_alloc_offset = cfg->stack_offset;
1532 #endif
1535 * Now allocate stack slots for the int arg regs (a0 - a3)
1536 * On MIPS o32, these are just above the incoming stack pointer
1537 * Even if the arg has been assigned to a regvar, it gets a stack slot
1540 /* Return struct-by-value results in a hidden first argument */
1541 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1542 cfg->vret_addr->opcode = OP_REGOFFSET;
1543 cfg->vret_addr->inst_c0 = mips_a0;
1544 cfg->vret_addr->inst_offset = offset;
1545 cfg->vret_addr->inst_basereg = frame_reg;
1546 offset += SIZEOF_REGISTER;
1549 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
1550 inst = cfg->args [i];
1551 if (inst->opcode != OP_REGVAR) {
1552 MonoType *arg_type;
1554 if (sig->hasthis && (i == 0))
1555 arg_type = mono_get_object_type ();
1556 else
1557 arg_type = sig->params [i - sig->hasthis];
1559 inst->opcode = OP_REGOFFSET;
1560 size = mono_type_size (arg_type, &align);
1562 if (size < SIZEOF_REGISTER) {
1563 size = SIZEOF_REGISTER;
1564 align = SIZEOF_REGISTER;
1566 inst->inst_basereg = frame_reg;
1567 offset = (offset + align - 1) & ~(align - 1);
1568 inst->inst_offset = offset;
1569 offset += size;
1570 if (cfg->verbose_level > 1)
1571 printf ("allocating param %d to fp[%d]\n", i, inst->inst_offset);
1573 else {
1574 #if _MIPS_SIM == _ABIO32
1575 /* o32: Even a0-a3 get stack slots */
1576 size = SIZEOF_REGISTER;
1577 align = SIZEOF_REGISTER;
1578 inst->inst_basereg = frame_reg;
1579 offset = (offset + align - 1) & ~(align - 1);
1580 inst->inst_offset = offset;
1581 offset += size;
1582 if (cfg->verbose_level > 1)
1583 printf ("allocating param %d to fp[%d]\n", i, inst->inst_offset);
1584 #endif
1587 #if _MIPS_SIM == _ABIN32
1588 /* Now add space for saving the ra */
1589 offset += TARGET_SIZEOF_VOID_P;
1591 /* change sign? */
1592 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1593 cfg->stack_offset = offset;
1594 cfg->arch.local_alloc_offset = cfg->stack_offset;
1595 #endif
1598 void
1599 mono_arch_create_vars (MonoCompile *cfg)
1601 MonoMethodSignature *sig;
1603 sig = mono_method_signature_internal (cfg->method);
1605 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1606 cfg->vret_addr = mono_compile_create_var (cfg, mono_get_int_type (), OP_ARG);
1607 if (G_UNLIKELY (cfg->verbose_level > 1)) {
1608 printf ("vret_addr = ");
1609 mono_print_ins (cfg->vret_addr);
1614 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1615 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1619 * take the arguments and generate the arch-specific
1620 * instructions to properly call the function in call.
1621 * This includes pushing, moving arguments to the right register
1622 * etc.
1623 * Issue: who does the spilling if needed, and when?
1625 static void
1626 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1628 MonoMethodSignature *tmp_sig;
1629 MonoInst *sig_arg;
1631 if (MONO_IS_TAILCALL_OPCODE (call))
1632 NOT_IMPLEMENTED;
1634 /* FIXME: Add support for signature tokens to AOT */
1635 cfg->disable_aot = TRUE;
1638 * mono_ArgIterator_Setup assumes the signature cookie is
1639 * passed first and all the arguments which were before it are
1640 * passed on the stack after the signature. So compensate by
1641 * passing a different signature.
1643 tmp_sig = mono_metadata_signature_dup (call->signature);
1644 tmp_sig->param_count -= call->signature->sentinelpos;
1645 tmp_sig->sentinelpos = 0;
1646 memcpy (tmp_sig->params, call->signature->params + call->signature->sentinelpos, tmp_sig->param_count * sizeof (MonoType*));
1648 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
1649 sig_arg->dreg = mono_alloc_ireg (cfg);
1650 sig_arg->inst_p0 = tmp_sig;
1651 MONO_ADD_INS (cfg->cbb, sig_arg);
1653 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_sp, cinfo->sig_cookie.offset, sig_arg->dreg);
1656 void
1657 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1659 MonoInst *in, *ins;
1660 MonoMethodSignature *sig;
1661 int i, n;
1662 CallInfo *cinfo;
1663 int is_virtual = 0;
1665 sig = call->signature;
1666 n = sig->param_count + sig->hasthis;
1668 cinfo = get_call_info (cfg->mempool, sig);
1669 if (cinfo->struct_ret)
1670 call->used_iregs |= 1 << cinfo->struct_ret;
1672 for (i = 0; i < n; ++i) {
1673 ArgInfo *ainfo = cinfo->args + i;
1674 MonoType *t;
1676 if (i >= sig->hasthis)
1677 t = sig->params [i - sig->hasthis];
1678 else
1679 t = mono_get_int_type ();
1680 t = mini_get_underlying_type (t);
1682 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1683 /* Emit the signature cookie just before the implicit arguments */
1684 emit_sig_cookie (cfg, call, cinfo);
1687 if (is_virtual && i == 0) {
1688 /* the argument will be attached to the call instrucion */
1689 in = call->args [i];
1690 call->used_iregs |= 1 << ainfo->reg;
1691 continue;
1693 in = call->args [i];
1694 if (ainfo->storage == ArgInIReg) {
1695 #if SIZEOF_REGISTER == 4
1696 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1697 MONO_INST_NEW (cfg, ins, OP_MOVE);
1698 ins->dreg = mono_alloc_ireg (cfg);
1699 ins->sreg1 = MONO_LVREG_LS (in->dreg);
1700 MONO_ADD_INS (cfg->cbb, ins);
1701 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + ls_word_idx, FALSE);
1703 MONO_INST_NEW (cfg, ins, OP_MOVE);
1704 ins->dreg = mono_alloc_ireg (cfg);
1705 ins->sreg1 = MONO_LVREG_MS (in->dreg);
1706 MONO_ADD_INS (cfg->cbb, ins);
1707 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + ms_word_idx, FALSE);
1708 } else
1709 #endif
1710 if (!t->byref && (t->type == MONO_TYPE_R4)) {
1711 int freg;
1713 #if PROMOTE_R4_TO_R8
1714 /* ??? - convert to single first? */
1715 MONO_INST_NEW (cfg, ins, OP_MIPS_CVTSD);
1716 ins->dreg = mono_alloc_freg (cfg);
1717 ins->sreg1 = in->dreg;
1718 MONO_ADD_INS (cfg->cbb, ins);
1719 freg = ins->dreg;
1720 #else
1721 freg = in->dreg;
1722 #endif
1723 /* trying to load float value into int registers */
1724 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1S);
1725 ins->dreg = mono_alloc_ireg (cfg);
1726 ins->sreg1 = freg;
1727 MONO_ADD_INS (cfg->cbb, ins);
1728 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1729 } else if (!t->byref && (t->type == MONO_TYPE_R8)) {
1730 /* trying to load float value into int registers */
1731 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1D);
1732 ins->dreg = mono_alloc_ireg (cfg);
1733 ins->sreg1 = in->dreg;
1734 MONO_ADD_INS (cfg->cbb, ins);
1735 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1736 } else {
1737 MONO_INST_NEW (cfg, ins, OP_MOVE);
1738 ins->dreg = mono_alloc_ireg (cfg);
1739 ins->sreg1 = in->dreg;
1740 MONO_ADD_INS (cfg->cbb, ins);
1741 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1743 } else if (ainfo->storage == ArgStructByAddr) {
1744 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1745 ins->opcode = OP_OUTARG_VT;
1746 ins->sreg1 = in->dreg;
1747 ins->klass = in->klass;
1748 ins->inst_p0 = call;
1749 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1750 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1751 MONO_ADD_INS (cfg->cbb, ins);
1752 } else if (ainfo->storage == ArgStructByVal) {
1753 /* this is further handled in mono_arch_emit_outarg_vt () */
1754 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1755 ins->opcode = OP_OUTARG_VT;
1756 ins->sreg1 = in->dreg;
1757 ins->klass = in->klass;
1758 ins->inst_p0 = call;
1759 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1760 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1761 MONO_ADD_INS (cfg->cbb, ins);
1762 } else if (ainfo->storage == ArgOnStack) {
1763 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1764 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1765 } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1766 if (t->type == MONO_TYPE_R8)
1767 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1768 else
1769 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1770 } else {
1771 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1773 } else if (ainfo->storage == ArgInFReg) {
1774 if (t->type == MONO_TYPE_VALUETYPE) {
1775 /* this is further handled in mono_arch_emit_outarg_vt () */
1776 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1777 ins->opcode = OP_OUTARG_VT;
1778 ins->sreg1 = in->dreg;
1779 ins->klass = in->klass;
1780 ins->inst_p0 = call;
1781 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1782 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1783 MONO_ADD_INS (cfg->cbb, ins);
1785 cfg->flags |= MONO_CFG_HAS_FPOUT;
1786 } else {
1787 int dreg = mono_alloc_freg (cfg);
1789 if (ainfo->size == 4) {
1790 MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, dreg, in->dreg);
1791 } else {
1792 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1793 ins->dreg = dreg;
1794 ins->sreg1 = in->dreg;
1795 MONO_ADD_INS (cfg->cbb, ins);
1798 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1799 cfg->flags |= MONO_CFG_HAS_FPOUT;
1801 } else {
1802 g_assert_not_reached ();
1806 /* Handle the case where there are no implicit arguments */
1807 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1808 emit_sig_cookie (cfg, call, cinfo);
1810 if (cinfo->struct_ret) {
1811 MonoInst *vtarg;
1813 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1814 vtarg->sreg1 = call->vret_var->dreg;
1815 vtarg->dreg = mono_alloc_preg (cfg);
1816 MONO_ADD_INS (cfg->cbb, vtarg);
1818 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1820 #if 0
1822 * Reverse the call->out_args list.
1825 MonoInst *prev = NULL, *list = call->out_args, *next;
1826 while (list) {
1827 next = list->next;
1828 list->next = prev;
1829 prev = list;
1830 list = next;
1832 call->out_args = prev;
1834 #endif
1835 call->stack_usage = cinfo->stack_usage;
1836 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1837 #if _MIPS_SIM == _ABIO32
1838 /* a0-a3 always present */
1839 cfg->param_area = MAX (cfg->param_area, 4 * SIZEOF_REGISTER);
1840 #endif
1841 cfg->param_area = (cfg->param_area + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1842 cfg->flags |= MONO_CFG_HAS_CALLS;
1844 * should set more info in call, such as the stack space
1845 * used by the args that needs to be added back to esp
1849 void
1850 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1852 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1853 ArgInfo *ainfo = ins->inst_p1;
1854 int ovf_size = ainfo->vtsize;
1855 int doffset = ainfo->offset;
1856 int i, soffset, dreg;
1858 if (ainfo->storage == ArgStructByVal) {
1859 #if 0
1860 if (cfg->verbose_level > 0) {
1861 char* nm = mono_method_full_name (cfg->method, TRUE);
1862 g_print ("Method %s outarg_vt struct doffset=%d ainfo->size=%d ovf_size=%d\n",
1863 nm, doffset, ainfo->size, ovf_size);
1864 g_free (nm);
1866 #endif
1868 soffset = 0;
1869 for (i = 0; i < ainfo->size; ++i) {
1870 dreg = mono_alloc_ireg (cfg);
1871 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1872 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1873 soffset += SIZEOF_REGISTER;
1875 if (ovf_size != 0) {
1876 mini_emit_memcpy (cfg, mips_sp, doffset, src->dreg, soffset, ovf_size * sizeof (target_mgreg_t), TARGET_SIZEOF_VOID_P);
1878 } else if (ainfo->storage == ArgInFReg) {
1879 int tmpr = mono_alloc_freg (cfg);
1881 if (ainfo->size == 4)
1882 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1883 else
1884 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1885 dreg = mono_alloc_freg (cfg);
1886 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1887 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1888 } else {
1889 MonoInst *vtcopy = mono_compile_create_var (cfg, m_class_get_byval_arg (src->klass), OP_LOCAL);
1890 MonoInst *load;
1891 guint32 size;
1893 /* FIXME: alignment? */
1894 if (call->signature->pinvoke) {
1895 size = mono_type_native_stack_size (m_class_get_byval_arg (src->klass), NULL);
1896 vtcopy->backend.is_pinvoke = 1;
1897 } else {
1898 size = mini_type_stack_size (m_class_get_byval_arg (src->klass), NULL);
1900 if (size > 0)
1901 g_assert (ovf_size > 0);
1903 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1904 mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, size, TARGET_SIZEOF_VOID_P);
1906 if (ainfo->offset)
1907 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_at, ainfo->offset, load->dreg);
1908 else
1909 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1913 void
1914 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1916 MonoType *ret = mini_get_underlying_type (mono_method_signature_internal (method)->ret);
1918 if (!ret->byref) {
1919 #if (SIZEOF_REGISTER == 4)
1920 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1921 MonoInst *ins;
1923 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1924 ins->sreg1 = MONO_LVREG_LS (val->dreg);
1925 ins->sreg2 = MONO_LVREG_MS (val->dreg);
1926 MONO_ADD_INS (cfg->cbb, ins);
1927 return;
1929 #endif
1930 if (ret->type == MONO_TYPE_R8) {
1931 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1932 return;
1934 if (ret->type == MONO_TYPE_R4) {
1935 MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, cfg->ret->dreg, val->dreg);
1936 return;
1939 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1942 void
1943 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1945 MonoInst *ins, *n, *last_ins = NULL;
1947 if (cfg->verbose_level > 2)
1948 g_print ("Basic block %d peephole pass 1\n", bb->block_num);
1950 ins = bb->code;
1951 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1952 if (cfg->verbose_level > 2)
1953 mono_print_ins_index (0, ins);
1955 switch (ins->opcode) {
1956 #if 0
1957 case OP_LOAD_MEMBASE:
1958 case OP_LOADI4_MEMBASE:
1960 * OP_IADD reg2, reg1, const1
1961 * OP_LOAD_MEMBASE const2(reg2), reg3
1962 * ->
1963 * OP_LOAD_MEMBASE (const1+const2)(reg1), reg3
1965 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)){
1966 int const1 = last_ins->inst_imm;
1967 int const2 = ins->inst_offset;
1969 if (mips_is_imm16 (const1 + const2)) {
1970 ins->inst_basereg = last_ins->sreg1;
1971 ins->inst_offset = const1 + const2;
1974 break;
1975 #endif
1978 last_ins = ins;
1979 ins = ins->next;
1981 bb->last_ins = last_ins;
1984 void
1985 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
1987 MonoInst *ins, *n, *last_ins = NULL;
1988 ins = bb->code;
1990 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1991 MonoInst *last_ins = ins->prev;
1993 switch (ins->opcode) {
1994 case OP_MUL_IMM:
1995 /* remove unnecessary multiplication with 1 */
1996 if (ins->inst_imm == 1) {
1997 if (ins->dreg != ins->sreg1) {
1998 ins->opcode = OP_MOVE;
1999 } else {
2000 MONO_DELETE_INS (bb, ins);
2001 continue;
2003 } else {
2004 int power2 = mono_is_power_of_two (ins->inst_imm);
2005 if (power2 > 0) {
2006 ins->opcode = OP_SHL_IMM;
2007 ins->inst_imm = power2;
2010 break;
2011 case OP_LOAD_MEMBASE:
2012 case OP_LOADI4_MEMBASE:
2014 * OP_STORE_MEMBASE_REG reg, offset(basereg)
2015 * OP_LOAD_MEMBASE offset(basereg), reg
2017 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
2018 || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
2019 ins->inst_basereg == last_ins->inst_destbasereg &&
2020 ins->inst_offset == last_ins->inst_offset) {
2021 if (ins->dreg == last_ins->sreg1) {
2022 MONO_DELETE_INS (bb, ins);
2023 continue;
2024 } else {
2025 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2026 ins->opcode = OP_MOVE;
2027 ins->sreg1 = last_ins->sreg1;
2029 break;
2032 * Note: reg1 must be different from the basereg in the second load
2033 * OP_LOAD_MEMBASE offset(basereg), reg1
2034 * OP_LOAD_MEMBASE offset(basereg), reg2
2035 * -->
2036 * OP_LOAD_MEMBASE offset(basereg), reg1
2037 * OP_MOVE reg1, reg2
2039 if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
2040 || last_ins->opcode == OP_LOAD_MEMBASE) &&
2041 ins->inst_basereg != last_ins->dreg &&
2042 ins->inst_basereg == last_ins->inst_basereg &&
2043 ins->inst_offset == last_ins->inst_offset) {
2045 if (ins->dreg == last_ins->dreg) {
2046 MONO_DELETE_INS (bb, ins);
2047 continue;
2048 } else {
2049 ins->opcode = OP_MOVE;
2050 ins->sreg1 = last_ins->dreg;
2053 //g_assert_not_reached ();
2054 break;
2056 #if 0
2058 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2059 * OP_LOAD_MEMBASE offset(basereg), reg
2060 * -->
2061 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2062 * OP_ICONST reg, imm
2064 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
2065 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
2066 ins->inst_basereg == last_ins->inst_destbasereg &&
2067 ins->inst_offset == last_ins->inst_offset) {
2068 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2069 ins->opcode = OP_ICONST;
2070 ins->inst_c0 = last_ins->inst_imm;
2071 g_assert_not_reached (); // check this rule
2072 break;
2074 #endif
2075 break;
2076 case OP_LOADU1_MEMBASE:
2077 case OP_LOADI1_MEMBASE:
2078 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
2079 ins->inst_basereg == last_ins->inst_destbasereg &&
2080 ins->inst_offset == last_ins->inst_offset) {
2081 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
2082 ins->sreg1 = last_ins->sreg1;
2084 break;
2085 case OP_LOADU2_MEMBASE:
2086 case OP_LOADI2_MEMBASE:
2087 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
2088 ins->inst_basereg == last_ins->inst_destbasereg &&
2089 ins->inst_offset == last_ins->inst_offset) {
2090 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
2091 ins->sreg1 = last_ins->sreg1;
2093 break;
2094 case OP_ICONV_TO_I4:
2095 case OP_ICONV_TO_U4:
2096 case OP_MOVE:
2097 ins->opcode = OP_MOVE;
2099 * OP_MOVE reg, reg
2101 if (ins->dreg == ins->sreg1) {
2102 MONO_DELETE_INS (bb, ins);
2103 continue;
2106 * OP_MOVE sreg, dreg
2107 * OP_MOVE dreg, sreg
2109 if (last_ins && last_ins->opcode == OP_MOVE &&
2110 ins->sreg1 == last_ins->dreg &&
2111 ins->dreg == last_ins->sreg1) {
2112 MONO_DELETE_INS (bb, ins);
2113 continue;
2115 break;
2117 last_ins = ins;
2118 ins = ins->next;
2120 bb->last_ins = last_ins;
2123 void
2124 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins)
2126 int tmp1 = -1;
2127 int tmp2 = -1;
2128 int tmp3 = -1;
2129 int tmp4 = -1;
2130 int tmp5 = -1;
2132 switch (ins->opcode) {
2133 case OP_LADD:
2134 tmp1 = mono_alloc_ireg (cfg);
2135 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2136 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2137 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2138 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
2139 NULLIFY_INS(ins);
2140 break;
2142 case OP_LADD_IMM:
2143 tmp1 = mono_alloc_ireg (cfg);
2144 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+1, ins->sreg1+1, ins_get_l_low (ins));
2145 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2146 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+2, ins->sreg1+2, ins_get_l_high (ins));
2147 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
2148 NULLIFY_INS(ins);
2149 break;
2151 case OP_LSUB:
2152 tmp1 = mono_alloc_ireg (cfg);
2153 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2154 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2155 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2156 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2157 NULLIFY_INS(ins);
2158 break;
2160 case OP_LSUB_IMM:
2161 tmp1 = mono_alloc_ireg (cfg);
2162 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+1, ins->sreg1+1, ins_get_l_low (ins));
2163 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2164 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+2, ins->sreg1+2, ins_get_l_high (ins));
2165 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2166 NULLIFY_INS(ins);
2167 break;
2169 case OP_LNEG:
2170 tmp1 = mono_alloc_ireg (cfg);
2171 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, mips_zero, ins->sreg1+1);
2172 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, mips_zero, ins->dreg+1);
2173 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, mips_zero, ins->sreg1+2);
2174 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2175 NULLIFY_INS(ins);
2176 break;
2178 case OP_LADD_OVF:
2179 tmp1 = mono_alloc_ireg (cfg);
2180 tmp2 = mono_alloc_ireg (cfg);
2181 tmp3 = mono_alloc_ireg (cfg);
2182 tmp4 = mono_alloc_ireg (cfg);
2183 tmp5 = mono_alloc_ireg (cfg);
2185 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2187 /* tmp1 holds the carry from the low 32-bit to the high 32-bits */
2188 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->dreg+1, ins->sreg1+1);
2190 /* add the high 32-bits, and add in the carry from the low 32-bits */
2191 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2192 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp5, ins->dreg+2);
2194 /* Overflow happens if
2195 * neg + neg = pos or
2196 * pos + pos = neg
2197 * XOR of the high bits returns 0 if the signs match
2198 * XOR of that with the high bit of the result return 1 if overflow.
2201 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2202 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2204 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2205 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg+2, ins->sreg2+2);
2206 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp2, tmp2);
2208 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2209 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp3, tmp2, tmp1);
2210 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2212 /* Now, if (tmp4 == 0) then overflow */
2213 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp4, mips_zero, "OverflowException");
2214 NULLIFY_INS(ins);
2215 break;
2217 case OP_LADD_OVF_UN:
2218 tmp1 = mono_alloc_ireg (cfg);
2219 tmp2 = mono_alloc_ireg (cfg);
2221 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2222 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2223 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2224 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp1, ins->dreg+2);
2225 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->dreg+2, ins->sreg1+2);
2226 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2227 NULLIFY_INS(ins);
2228 break;
2230 case OP_LSUB_OVF:
2231 tmp1 = mono_alloc_ireg (cfg);
2232 tmp2 = mono_alloc_ireg (cfg);
2233 tmp3 = mono_alloc_ireg (cfg);
2234 tmp4 = mono_alloc_ireg (cfg);
2235 tmp5 = mono_alloc_ireg (cfg);
2237 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2239 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->sreg1+1, ins->dreg+1);
2240 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2241 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp5);
2243 /* Overflow happens if
2244 * neg - pos = pos or
2245 * pos - neg = neg
2246 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2248 * tmp1 = (lhs ^ rhs)
2249 * tmp2 = (lhs ^ result)
2250 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2253 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2254 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1+2, ins->dreg+2);
2255 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp3, tmp2, tmp1);
2256 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2258 /* Now, if (tmp4 == 1) then overflow */
2259 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp4, mips_zero, "OverflowException");
2260 NULLIFY_INS(ins);
2261 break;
2263 case OP_LSUB_OVF_UN:
2264 tmp1 = mono_alloc_ireg (cfg);
2265 tmp2 = mono_alloc_ireg (cfg);
2267 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2268 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2269 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2270 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2272 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->sreg1+2, ins->dreg+2);
2273 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2274 NULLIFY_INS(ins);
2275 break;
2276 case OP_LCONV_TO_OVF_I4_2:
2277 tmp1 = mono_alloc_ireg (cfg);
2279 /* Overflows if reg2 != sign extension of reg1 */
2280 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp1, ins->sreg1, 31);
2281 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, ins->sreg2, tmp1, "OverflowException");
2282 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
2283 NULLIFY_INS(ins);
2284 break;
2285 default:
2286 break;
2290 void
2291 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
2293 int tmp1 = -1;
2294 int tmp2 = -1;
2295 int tmp3 = -1;
2296 int tmp4 = -1;
2297 int tmp5 = -1;
2299 switch (ins->opcode) {
2300 case OP_IADD_OVF:
2301 tmp1 = mono_alloc_ireg (cfg);
2302 tmp2 = mono_alloc_ireg (cfg);
2303 tmp3 = mono_alloc_ireg (cfg);
2304 tmp4 = mono_alloc_ireg (cfg);
2305 tmp5 = mono_alloc_ireg (cfg);
2307 /* add the operands */
2309 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2311 /* Overflow happens if
2312 * neg + neg = pos or
2313 * pos + pos = neg
2315 * (bit31s of operands match) AND (bit31 of operand != bit31 of result)
2316 * XOR of the high bit returns 0 if the signs match
2317 * XOR of that with the high bit of the result return 1 if overflow.
2320 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2321 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2323 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2324 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg, ins->sreg2);
2325 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp3, tmp2);
2327 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2328 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp4, tmp3, tmp1);
2330 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp5, tmp4, 31);
2332 /* Now, if (tmp5 == 0) then overflow */
2333 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp5, mips_zero, "OverflowException");
2334 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2335 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2336 NULLIFY_INS(ins);
2337 break;
2339 case OP_IADD_OVF_UN:
2340 tmp1 = mono_alloc_ireg (cfg);
2342 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2343 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg, ins->sreg1);
2344 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2345 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2346 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2347 NULLIFY_INS(ins);
2348 break;
2350 case OP_ISUB_OVF:
2351 tmp1 = mono_alloc_ireg (cfg);
2352 tmp2 = mono_alloc_ireg (cfg);
2353 tmp3 = mono_alloc_ireg (cfg);
2354 tmp4 = mono_alloc_ireg (cfg);
2355 tmp5 = mono_alloc_ireg (cfg);
2357 /* add the operands */
2359 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2361 /* Overflow happens if
2362 * neg - pos = pos or
2363 * pos - neg = neg
2364 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2366 * tmp1 = (lhs ^ rhs)
2367 * tmp2 = (lhs ^ result)
2368 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2371 /* tmp3 = 1 if the signs of the two inputs differ */
2372 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2373 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1, ins->dreg);
2374 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp3, tmp1, 0);
2375 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp4, tmp2, 0);
2376 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp5, tmp4, tmp3);
2378 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp5, mips_zero, "OverflowException");
2379 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2380 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2381 NULLIFY_INS(ins);
2382 break;
2384 case OP_ISUB_OVF_UN:
2385 tmp1 = mono_alloc_ireg (cfg);
2387 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2388 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1, ins->dreg);
2389 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2390 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2391 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2392 NULLIFY_INS(ins);
2393 break;
2397 static int
2398 map_to_reg_reg_op (int op)
2400 switch (op) {
2401 case OP_ADD_IMM:
2402 return OP_IADD;
2403 case OP_SUB_IMM:
2404 return OP_ISUB;
2405 case OP_AND_IMM:
2406 return OP_IAND;
2407 case OP_COMPARE_IMM:
2408 return OP_COMPARE;
2409 case OP_ICOMPARE_IMM:
2410 return OP_ICOMPARE;
2411 case OP_LCOMPARE_IMM:
2412 return OP_LCOMPARE;
2413 case OP_ADDCC_IMM:
2414 return OP_IADDCC;
2415 case OP_ADC_IMM:
2416 return OP_IADC;
2417 case OP_SUBCC_IMM:
2418 return OP_ISUBCC;
2419 case OP_SBB_IMM:
2420 return OP_ISBB;
2421 case OP_OR_IMM:
2422 return OP_IOR;
2423 case OP_XOR_IMM:
2424 return OP_IXOR;
2425 case OP_MUL_IMM:
2426 return OP_IMUL;
2427 case OP_LOAD_MEMBASE:
2428 return OP_LOAD_MEMINDEX;
2429 case OP_LOADI4_MEMBASE:
2430 return OP_LOADI4_MEMINDEX;
2431 case OP_LOADU4_MEMBASE:
2432 return OP_LOADU4_MEMINDEX;
2433 case OP_LOADU1_MEMBASE:
2434 return OP_LOADU1_MEMINDEX;
2435 case OP_LOADI2_MEMBASE:
2436 return OP_LOADI2_MEMINDEX;
2437 case OP_LOADU2_MEMBASE:
2438 return OP_LOADU2_MEMINDEX;
2439 case OP_LOADI1_MEMBASE:
2440 return OP_LOADI1_MEMINDEX;
2441 case OP_LOADR4_MEMBASE:
2442 return OP_LOADR4_MEMINDEX;
2443 case OP_LOADR8_MEMBASE:
2444 return OP_LOADR8_MEMINDEX;
2445 case OP_STOREI1_MEMBASE_REG:
2446 return OP_STOREI1_MEMINDEX;
2447 case OP_STOREI2_MEMBASE_REG:
2448 return OP_STOREI2_MEMINDEX;
2449 case OP_STOREI4_MEMBASE_REG:
2450 return OP_STOREI4_MEMINDEX;
2451 case OP_STORE_MEMBASE_REG:
2452 return OP_STORE_MEMINDEX;
2453 case OP_STORER4_MEMBASE_REG:
2454 return OP_STORER4_MEMINDEX;
2455 case OP_STORER8_MEMBASE_REG:
2456 return OP_STORER8_MEMINDEX;
2457 case OP_STORE_MEMBASE_IMM:
2458 return OP_STORE_MEMBASE_REG;
2459 case OP_STOREI1_MEMBASE_IMM:
2460 return OP_STOREI1_MEMBASE_REG;
2461 case OP_STOREI2_MEMBASE_IMM:
2462 return OP_STOREI2_MEMBASE_REG;
2463 case OP_STOREI4_MEMBASE_IMM:
2464 return OP_STOREI4_MEMBASE_REG;
2465 case OP_STOREI8_MEMBASE_IMM:
2466 return OP_STOREI8_MEMBASE_REG;
2468 if (mono_op_imm_to_op (op) == -1)
2469 g_error ("mono_op_imm_to_op failed for %s\n", mono_inst_name (op));
2470 return mono_op_imm_to_op (op);
2473 static int
2474 map_to_mips_op (int op)
2476 switch (op) {
2477 case OP_FBEQ:
2478 return OP_MIPS_FBEQ;
2479 case OP_FBGE:
2480 return OP_MIPS_FBGE;
2481 case OP_FBGT:
2482 return OP_MIPS_FBGT;
2483 case OP_FBLE:
2484 return OP_MIPS_FBLE;
2485 case OP_FBLT:
2486 return OP_MIPS_FBLT;
2487 case OP_FBNE_UN:
2488 return OP_MIPS_FBNE;
2489 case OP_FBGE_UN:
2490 return OP_MIPS_FBGE_UN;
2491 case OP_FBGT_UN:
2492 return OP_MIPS_FBGT_UN;
2493 case OP_FBLE_UN:
2494 return OP_MIPS_FBLE_UN;
2495 case OP_FBLT_UN:
2496 return OP_MIPS_FBLT_UN;
2498 case OP_FCEQ:
2499 case OP_FCGT:
2500 case OP_FCGT_UN:
2501 case OP_FCLT:
2502 case OP_FCLT_UN:
2503 default:
2504 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (op), __FUNCTION__);
2505 g_assert_not_reached ();
2509 #define NEW_INS(cfg,after,dest,op) do { \
2510 MONO_INST_NEW((cfg), (dest), (op)); \
2511 mono_bblock_insert_after_ins (bb, (after), (dest)); \
2512 } while (0)
2514 #define INS(pos,op,_dreg,_sreg1,_sreg2) do { \
2515 MonoInst *temp; \
2516 MONO_INST_NEW(cfg, temp, (op)); \
2517 mono_bblock_insert_after_ins (bb, (pos), temp); \
2518 temp->dreg = (_dreg); \
2519 temp->sreg1 = (_sreg1); \
2520 temp->sreg2 = (_sreg2); \
2521 pos = temp; \
2522 } while (0)
2524 #define INS_IMM(pos,op,_dreg,_sreg1,_imm) do { \
2525 MonoInst *temp; \
2526 MONO_INST_NEW(cfg, temp, (op)); \
2527 mono_bblock_insert_after_ins (bb, (pos), temp); \
2528 temp->dreg = (_dreg); \
2529 temp->sreg1 = (_sreg1); \
2530 temp->inst_c0 = (_imm); \
2531 pos = temp; \
2532 } while (0)
2535 * Remove from the instruction list the instructions that can't be
2536 * represented with very simple instructions with no register
2537 * requirements.
2539 void
2540 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2542 MonoInst *ins, *next, *temp, *last_ins = NULL;
2543 int imm;
2545 #if 1
2546 if (cfg->verbose_level > 2) {
2547 int idx = 0;
2549 g_print ("BASIC BLOCK %d (before lowering)\n", bb->block_num);
2550 MONO_BB_FOR_EACH_INS (bb, ins) {
2551 mono_print_ins_index (idx++, ins);
2555 #endif
2557 MONO_BB_FOR_EACH_INS (bb, ins) {
2558 loop_start:
2559 switch (ins->opcode) {
2560 case OP_COMPARE:
2561 case OP_ICOMPARE:
2562 case OP_LCOMPARE:
2563 next = ins->next;
2564 /* Branch opts can eliminate the branch */
2565 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2566 NULLIFY_INS(ins);
2567 break;
2569 break;
2571 case OP_COMPARE_IMM:
2572 case OP_ICOMPARE_IMM:
2573 case OP_LCOMPARE_IMM:
2574 next = ins->next;
2575 /* Branch opts can eliminate the branch */
2576 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2577 NULLIFY_INS(ins);
2578 break;
2580 if (ins->inst_imm) {
2581 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2582 temp->inst_c0 = ins->inst_imm;
2583 temp->dreg = mono_alloc_ireg (cfg);
2584 ins->sreg2 = temp->dreg;
2585 last_ins = temp;
2587 else {
2588 ins->sreg2 = mips_zero;
2590 if (ins->opcode == OP_COMPARE_IMM)
2591 ins->opcode = OP_COMPARE;
2592 else if (ins->opcode == OP_ICOMPARE_IMM)
2593 ins->opcode = OP_ICOMPARE;
2594 else if (ins->opcode == OP_LCOMPARE_IMM)
2595 ins->opcode = OP_LCOMPARE;
2596 goto loop_start;
2598 case OP_IDIV_UN_IMM:
2599 case OP_IDIV_IMM:
2600 case OP_IREM_IMM:
2601 case OP_IREM_UN_IMM:
2602 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2603 temp->inst_c0 = ins->inst_imm;
2604 temp->dreg = mono_alloc_ireg (cfg);
2605 ins->sreg2 = temp->dreg;
2606 if (ins->opcode == OP_IDIV_IMM)
2607 ins->opcode = OP_IDIV;
2608 else if (ins->opcode == OP_IREM_IMM)
2609 ins->opcode = OP_IREM;
2610 else if (ins->opcode == OP_IDIV_UN_IMM)
2611 ins->opcode = OP_IDIV_UN;
2612 else if (ins->opcode == OP_IREM_UN_IMM)
2613 ins->opcode = OP_IREM_UN;
2614 last_ins = temp;
2615 /* handle rem separately */
2616 goto loop_start;
2618 #if 0
2619 case OP_AND_IMM:
2620 case OP_OR_IMM:
2621 case OP_XOR_IMM:
2622 if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
2623 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2624 temp->inst_c0 = ins->inst_imm;
2625 temp->dreg = mono_alloc_ireg (cfg);
2626 ins->sreg2 = temp->dreg;
2627 ins->opcode = map_to_reg_reg_op (ins->opcode);
2629 break;
2630 #endif
2631 case OP_AND_IMM:
2632 case OP_IAND_IMM:
2633 case OP_OR_IMM:
2634 case OP_IOR_IMM:
2635 case OP_XOR_IMM:
2636 case OP_IXOR_IMM:
2637 /* unsigned 16 bit immediate */
2638 if (ins->inst_imm & 0xffff0000) {
2639 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2640 temp->inst_c0 = ins->inst_imm;
2641 temp->dreg = mono_alloc_ireg (cfg);
2642 ins->sreg2 = temp->dreg;
2643 ins->opcode = map_to_reg_reg_op (ins->opcode);
2645 break;
2647 case OP_IADD_IMM:
2648 case OP_ADD_IMM:
2649 case OP_ADDCC_IMM:
2650 /* signed 16 bit immediate */
2651 if (!mips_is_imm16 (ins->inst_imm)) {
2652 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2653 temp->inst_c0 = ins->inst_imm;
2654 temp->dreg = mono_alloc_ireg (cfg);
2655 ins->sreg2 = temp->dreg;
2656 ins->opcode = map_to_reg_reg_op (ins->opcode);
2658 break;
2660 case OP_SUB_IMM:
2661 case OP_ISUB_IMM:
2662 if (!mips_is_imm16 (-ins->inst_imm)) {
2663 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2664 temp->inst_c0 = ins->inst_imm;
2665 temp->dreg = mono_alloc_ireg (cfg);
2666 ins->sreg2 = temp->dreg;
2667 ins->opcode = map_to_reg_reg_op (ins->opcode);
2669 break;
2671 case OP_MUL_IMM:
2672 case OP_IMUL_IMM:
2673 if (ins->inst_imm == 1) {
2674 ins->opcode = OP_MOVE;
2675 break;
2677 if (ins->inst_imm == 0) {
2678 ins->opcode = OP_ICONST;
2679 ins->inst_c0 = 0;
2680 break;
2682 imm = mono_is_power_of_two (ins->inst_imm);
2683 if (imm > 0) {
2684 ins->opcode = OP_SHL_IMM;
2685 ins->inst_imm = imm;
2686 break;
2688 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2689 temp->inst_c0 = ins->inst_imm;
2690 temp->dreg = mono_alloc_ireg (cfg);
2691 ins->sreg2 = temp->dreg;
2692 ins->opcode = map_to_reg_reg_op (ins->opcode);
2693 break;
2695 case OP_LOCALLOC_IMM:
2696 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2697 temp->inst_c0 = ins->inst_imm;
2698 temp->dreg = mono_alloc_ireg (cfg);
2699 ins->sreg1 = temp->dreg;
2700 ins->opcode = OP_LOCALLOC;
2701 break;
2703 case OP_LOADR4_MEMBASE:
2704 case OP_STORER4_MEMBASE_REG:
2705 /* we can do two things: load the immed in a register
2706 * and use an indexed load, or see if the immed can be
2707 * represented as an ad_imm + a load with a smaller offset
2708 * that fits. We just do the first for now, optimize later.
2710 if (mips_is_imm16 (ins->inst_offset))
2711 break;
2712 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2713 temp->inst_c0 = ins->inst_offset;
2714 temp->dreg = mono_alloc_ireg (cfg);
2715 ins->sreg2 = temp->dreg;
2716 ins->opcode = map_to_reg_reg_op (ins->opcode);
2717 break;
2719 case OP_STORE_MEMBASE_IMM:
2720 case OP_STOREI1_MEMBASE_IMM:
2721 case OP_STOREI2_MEMBASE_IMM:
2722 case OP_STOREI4_MEMBASE_IMM:
2723 case OP_STOREI8_MEMBASE_IMM:
2724 if (!ins->inst_imm) {
2725 ins->sreg1 = mips_zero;
2726 ins->opcode = map_to_reg_reg_op (ins->opcode);
2728 else {
2729 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2730 temp->inst_c0 = ins->inst_imm;
2731 temp->dreg = mono_alloc_ireg (cfg);
2732 ins->sreg1 = temp->dreg;
2733 ins->opcode = map_to_reg_reg_op (ins->opcode);
2734 last_ins = temp;
2735 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2737 break;
2739 case OP_FCOMPARE:
2740 next = ins->next;
2741 /* Branch opts can eliminate the branch */
2742 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2743 NULLIFY_INS(ins);
2744 break;
2746 g_assert(next);
2749 * remap compare/branch and compare/set
2750 * to MIPS specific opcodes.
2752 next->opcode = map_to_mips_op (next->opcode);
2753 next->sreg1 = ins->sreg1;
2754 next->sreg2 = ins->sreg2;
2755 NULLIFY_INS(ins);
2756 break;
2758 #if 0
2759 case OP_R8CONST:
2760 case OP_R4CONST:
2761 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2762 temp->inst_c0 = (guint32)ins->inst_p0;
2763 temp->dreg = mono_alloc_ireg (cfg);
2764 ins->inst_basereg = temp->dreg;
2765 ins->inst_offset = 0;
2766 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2767 last_ins = temp;
2768 /* make it handle the possibly big ins->inst_offset
2769 * later optimize to use lis + load_membase
2771 goto loop_start;
2772 #endif
2773 case OP_IBEQ:
2774 g_assert (ins_is_compare(last_ins));
2775 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->sreg1, last_ins->sreg2);
2776 NULLIFY_INS(last_ins);
2777 break;
2779 case OP_IBNE_UN:
2780 g_assert (ins_is_compare(last_ins));
2781 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->sreg1, last_ins->sreg2);
2782 NULLIFY_INS(last_ins);
2783 break;
2785 case OP_IBGE:
2786 g_assert (ins_is_compare(last_ins));
2787 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2788 last_ins->dreg = mono_alloc_ireg (cfg);
2789 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2790 break;
2792 case OP_IBGE_UN:
2793 g_assert (ins_is_compare(last_ins));
2794 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2795 last_ins->dreg = mono_alloc_ireg (cfg);
2796 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2797 break;
2799 case OP_IBLT:
2800 g_assert (ins_is_compare(last_ins));
2801 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2802 last_ins->dreg = mono_alloc_ireg (cfg);
2803 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2804 break;
2806 case OP_IBLT_UN:
2807 g_assert (ins_is_compare(last_ins));
2808 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2809 last_ins->dreg = mono_alloc_ireg (cfg);
2810 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2811 break;
2813 case OP_IBLE:
2814 g_assert (ins_is_compare(last_ins));
2815 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2816 last_ins->dreg = mono_alloc_ireg (cfg);
2817 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2818 break;
2820 case OP_IBLE_UN:
2821 g_assert (ins_is_compare(last_ins));
2822 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2823 last_ins->dreg = mono_alloc_ireg (cfg);
2824 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2825 break;
2827 case OP_IBGT:
2828 g_assert (ins_is_compare(last_ins));
2829 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2830 last_ins->dreg = mono_alloc_ireg (cfg);
2831 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2832 break;
2834 case OP_IBGT_UN:
2835 g_assert (ins_is_compare(last_ins));
2836 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2837 last_ins->dreg = mono_alloc_ireg (cfg);
2838 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2839 break;
2841 case OP_CEQ:
2842 case OP_ICEQ:
2843 g_assert (ins_is_compare(last_ins));
2844 last_ins->opcode = OP_IXOR;
2845 last_ins->dreg = mono_alloc_ireg(cfg);
2846 INS_REWRITE_IMM(ins, OP_MIPS_SLTIU, last_ins->dreg, 1);
2847 break;
2849 case OP_CLT:
2850 case OP_ICLT:
2851 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2852 NULLIFY_INS(last_ins);
2853 break;
2856 case OP_CLT_UN:
2857 case OP_ICLT_UN:
2858 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2859 NULLIFY_INS(last_ins);
2860 break;
2862 case OP_CGT:
2863 case OP_ICGT:
2864 g_assert (ins_is_compare(last_ins));
2865 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2866 MONO_DELETE_INS(bb, last_ins);
2867 break;
2869 case OP_CGT_UN:
2870 case OP_ICGT_UN:
2871 g_assert (ins_is_compare(last_ins));
2872 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2873 MONO_DELETE_INS(bb, last_ins);
2874 break;
2876 case OP_COND_EXC_EQ:
2877 case OP_COND_EXC_IEQ:
2878 g_assert (ins_is_compare(last_ins));
2879 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, last_ins->sreg1, last_ins->sreg2);
2880 MONO_DELETE_INS(bb, last_ins);
2881 break;
2883 case OP_COND_EXC_GE:
2884 case OP_COND_EXC_IGE:
2885 g_assert (ins_is_compare(last_ins));
2886 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE, last_ins->sreg1, last_ins->sreg2);
2887 MONO_DELETE_INS(bb, last_ins);
2888 break;
2890 case OP_COND_EXC_GT:
2891 case OP_COND_EXC_IGT:
2892 g_assert (ins_is_compare(last_ins));
2893 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT, last_ins->sreg1, last_ins->sreg2);
2894 MONO_DELETE_INS(bb, last_ins);
2895 break;
2897 case OP_COND_EXC_LE:
2898 case OP_COND_EXC_ILE:
2899 g_assert (ins_is_compare(last_ins));
2900 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE, last_ins->sreg1, last_ins->sreg2);
2901 MONO_DELETE_INS(bb, last_ins);
2902 break;
2904 case OP_COND_EXC_LT:
2905 case OP_COND_EXC_ILT:
2906 g_assert (ins_is_compare(last_ins));
2907 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT, last_ins->sreg1, last_ins->sreg2);
2908 MONO_DELETE_INS(bb, last_ins);
2909 break;
2911 case OP_COND_EXC_NE_UN:
2912 case OP_COND_EXC_INE_UN:
2913 g_assert (ins_is_compare(last_ins));
2914 INS_REWRITE(ins, OP_MIPS_COND_EXC_NE_UN, last_ins->sreg1, last_ins->sreg2);
2915 MONO_DELETE_INS(bb, last_ins);
2916 break;
2918 case OP_COND_EXC_GE_UN:
2919 case OP_COND_EXC_IGE_UN:
2920 g_assert (ins_is_compare(last_ins));
2921 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE_UN, last_ins->sreg1, last_ins->sreg2);
2922 MONO_DELETE_INS(bb, last_ins);
2923 break;
2925 case OP_COND_EXC_GT_UN:
2926 case OP_COND_EXC_IGT_UN:
2927 g_assert (ins_is_compare(last_ins));
2928 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT_UN, last_ins->sreg1, last_ins->sreg2);
2929 MONO_DELETE_INS(bb, last_ins);
2930 break;
2932 case OP_COND_EXC_LE_UN:
2933 case OP_COND_EXC_ILE_UN:
2934 g_assert (ins_is_compare(last_ins));
2935 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE_UN, last_ins->sreg1, last_ins->sreg2);
2936 MONO_DELETE_INS(bb, last_ins);
2937 break;
2939 case OP_COND_EXC_LT_UN:
2940 case OP_COND_EXC_ILT_UN:
2941 g_assert (ins_is_compare(last_ins));
2942 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT_UN, last_ins->sreg1, last_ins->sreg2);
2943 MONO_DELETE_INS(bb, last_ins);
2944 break;
2946 case OP_COND_EXC_OV:
2947 case OP_COND_EXC_IOV: {
2948 int tmp1, tmp2, tmp3, tmp4, tmp5;
2949 MonoInst *pos = last_ins;
2951 /* Overflow happens if
2952 * neg + neg = pos or
2953 * pos + pos = neg
2955 * (bit31s of operands match) AND (bit31 of operand
2956 * != bit31 of result)
2957 * XOR of the high bit returns 0 if the signs match
2958 * XOR of that with the high bit of the result return 1
2959 * if overflow.
2961 g_assert (last_ins->opcode == OP_IADC);
2963 tmp1 = mono_alloc_ireg (cfg);
2964 tmp2 = mono_alloc_ireg (cfg);
2965 tmp3 = mono_alloc_ireg (cfg);
2966 tmp4 = mono_alloc_ireg (cfg);
2967 tmp5 = mono_alloc_ireg (cfg);
2969 /* tmp1 = 0 if the signs of the two inputs match, else 1 */
2970 INS (pos, OP_IXOR, tmp1, last_ins->sreg1, last_ins->sreg2);
2972 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2973 INS (pos, OP_IXOR, tmp2, last_ins->dreg, last_ins->sreg2);
2974 INS (pos, OP_INOT, tmp3, tmp2, -1);
2976 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2977 INS (pos, OP_IOR, tmp4, tmp3, tmp1);
2978 INS_IMM (pos, OP_SHR_IMM, tmp5, tmp4, 31);
2980 /* Now, if (tmp5 == 0) then overflow */
2981 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, tmp5, mips_zero);
2982 ins->dreg = -1;
2983 break;
2986 case OP_COND_EXC_NO:
2987 case OP_COND_EXC_INO:
2988 g_assert_not_reached ();
2989 break;
2991 case OP_COND_EXC_C:
2992 case OP_COND_EXC_IC:
2993 g_assert_not_reached ();
2994 break;
2996 case OP_COND_EXC_NC:
2997 case OP_COND_EXC_INC:
2998 g_assert_not_reached ();
2999 break;
3002 last_ins = ins;
3004 bb->last_ins = last_ins;
3005 bb->max_vreg = cfg->next_vreg;
3007 #if 1
3008 if (cfg->verbose_level > 2) {
3009 int idx = 0;
3011 g_print ("BASIC BLOCK %d (after lowering)\n", bb->block_num);
3012 MONO_BB_FOR_EACH_INS (bb, ins) {
3013 mono_print_ins_index (idx++, ins);
3017 #endif
3021 static guchar*
3022 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
3024 /* sreg is a float, dreg is an integer reg. mips_at is used as scratch */
3025 #if 1
3026 mips_truncwd (code, mips_ftemp, sreg);
3027 #else
3028 mips_cvtwd (code, mips_ftemp, sreg);
3029 #endif
3030 mips_mfc1 (code, dreg, mips_ftemp);
3031 if (!is_signed) {
3032 if (size == 1)
3033 mips_andi (code, dreg, dreg, 0xff);
3034 else if (size == 2) {
3035 mips_sll (code, dreg, dreg, 16);
3036 mips_srl (code, dreg, dreg, 16);
3038 } else {
3039 if (size == 1) {
3040 mips_sll (code, dreg, dreg, 24);
3041 mips_sra (code, dreg, dreg, 24);
3043 else if (size == 2) {
3044 mips_sll (code, dreg, dreg, 16);
3045 mips_sra (code, dreg, dreg, 16);
3048 return code;
3052 * emit_load_volatile_arguments:
3054 * Load volatile arguments from the stack to the original input registers.
3055 * Required before a tailcall.
3057 static guint8 *
3058 emit_load_volatile_arguments(MonoCompile *cfg, guint8 *code)
3060 MonoMethod *method = cfg->method;
3061 MonoMethodSignature *sig;
3062 MonoInst *inst;
3063 CallInfo *cinfo;
3064 int i;
3066 sig = mono_method_signature_internal (method);
3068 if (!cfg->arch.cinfo)
3069 cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
3070 cinfo = cfg->arch.cinfo;
3072 if (cinfo->struct_ret) {
3073 ArgInfo *ainfo = &cinfo->ret;
3074 inst = cfg->vret_addr;
3075 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3078 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3079 ArgInfo *ainfo = cinfo->args + i;
3080 inst = cfg->args [i];
3081 if (inst->opcode == OP_REGVAR) {
3082 if (ainfo->storage == ArgInIReg)
3083 MIPS_MOVE (code, ainfo->reg, inst->dreg);
3084 else if (ainfo->storage == ArgInFReg)
3085 g_assert_not_reached();
3086 else if (ainfo->storage == ArgOnStack) {
3087 /* do nothing */
3088 } else
3089 g_assert_not_reached ();
3090 } else {
3091 if (ainfo->storage == ArgInIReg) {
3092 g_assert (mips_is_imm16 (inst->inst_offset));
3093 switch (ainfo->size) {
3094 case 1:
3095 mips_lb (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3096 break;
3097 case 2:
3098 mips_lh (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3099 break;
3100 case 0: /* XXX */
3101 case 4:
3102 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3103 break;
3104 case 8:
3105 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
3106 mips_lw (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
3107 break;
3108 default:
3109 g_assert_not_reached ();
3110 break;
3112 } else if (ainfo->storage == ArgOnStack) {
3113 /* do nothing */
3114 } else if (ainfo->storage == ArgInFReg) {
3115 g_assert (mips_is_imm16 (inst->inst_offset));
3116 if (ainfo->size == 8) {
3117 #if _MIPS_SIM == _ABIO32
3118 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
3119 mips_lwc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
3120 #elif _MIPS_SIM == _ABIN32
3121 mips_ldc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3122 #endif
3124 else if (ainfo->size == 4)
3125 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3126 else
3127 g_assert_not_reached ();
3128 } else if (ainfo->storage == ArgStructByVal) {
3129 int i;
3130 int doffset = inst->inst_offset;
3132 g_assert (mips_is_imm16 (inst->inst_offset));
3133 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (target_mgreg_t)));
3134 for (i = 0; i < ainfo->size; ++i) {
3135 mips_lw (code, ainfo->reg + i, inst->inst_basereg, doffset);
3136 doffset += SIZEOF_REGISTER;
3138 } else if (ainfo->storage == ArgStructByAddr) {
3139 g_assert (mips_is_imm16 (inst->inst_offset));
3140 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3141 } else
3142 g_assert_not_reached ();
3146 return code;
3149 static guint8*
3150 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
3152 int size = cfg->param_area;
3154 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3155 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3157 if (!size)
3158 return code;
3159 #if 0
3160 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3161 if (ppc_is_imm16 (-size)) {
3162 ppc_stwu (code, ppc_r0, -size, ppc_sp);
3163 } else {
3164 ppc_load (code, ppc_r12, -size);
3165 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r12);
3167 #endif
3168 return code;
3171 static guint8*
3172 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
3174 int size = cfg->param_area;
3176 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3177 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3179 if (!size)
3180 return code;
3181 #if 0
3182 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3183 if (ppc_is_imm16 (size)) {
3184 ppc_stwu (code, ppc_r0, size, ppc_sp);
3185 } else {
3186 ppc_load (code, ppc_r12, size);
3187 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r12);
3189 #endif
3190 return code;
3193 void
3194 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3196 MonoInst *ins;
3197 MonoCallInst *call;
3198 guint8 *code = cfg->native_code + cfg->code_len;
3199 MonoInst *last_ins = NULL;
3200 int max_len, cpos;
3201 int ins_cnt = 0;
3203 /* we don't align basic blocks of loops on mips */
3205 if (cfg->verbose_level > 2)
3206 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3208 cpos = bb->max_offset;
3210 MONO_BB_FOR_EACH_INS (bb, ins) {
3211 const guint offset = code - cfg->native_code;
3212 set_code_cursor (cfg, code);
3213 max_len = ins_get_size (ins->opcode);
3214 code = realloc_code (cfg, max_len);
3216 mono_debug_record_line_number (cfg, ins, offset);
3217 if (cfg->verbose_level > 2) {
3218 g_print (" @ 0x%x\t", offset);
3219 mono_print_ins_index (ins_cnt++, ins);
3221 /* Check for virtual regs that snuck by */
3222 g_assert ((ins->dreg >= -1) && (ins->dreg < 32));
3224 switch (ins->opcode) {
3225 case OP_RELAXED_NOP:
3226 case OP_NOP:
3227 case OP_DUMMY_USE:
3228 case OP_DUMMY_ICONST:
3229 case OP_DUMMY_I8CONST:
3230 case OP_DUMMY_R8CONST:
3231 case OP_DUMMY_R4CONST:
3232 case OP_NOT_REACHED:
3233 case OP_NOT_NULL:
3234 break;
3235 case OP_IL_SEQ_POINT:
3236 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3237 break;
3238 case OP_SEQ_POINT: {
3239 if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
3240 guint32 addr = (guint32)ss_trigger_page;
3242 mips_load_const (code, mips_t9, addr);
3243 mips_lw (code, mips_t9, mips_t9, 0);
3246 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3249 * A placeholder for a possible breakpoint inserted by
3250 * mono_arch_set_breakpoint ().
3252 /* mips_load_const () + mips_lw */
3253 mips_nop (code);
3254 mips_nop (code);
3255 mips_nop (code);
3256 break;
3258 case OP_BIGMUL:
3259 mips_mult (code, ins->sreg1, ins->sreg2);
3260 mips_mflo (code, ins->dreg);
3261 mips_mfhi (code, ins->dreg+1);
3262 break;
3263 case OP_BIGMUL_UN:
3264 mips_multu (code, ins->sreg1, ins->sreg2);
3265 mips_mflo (code, ins->dreg);
3266 mips_mfhi (code, ins->dreg+1);
3267 break;
3268 case OP_MEMORY_BARRIER:
3269 mips_sync (code, 0);
3270 break;
3271 case OP_STOREI1_MEMBASE_IMM:
3272 mips_load_const (code, mips_temp, ins->inst_imm);
3273 if (mips_is_imm16 (ins->inst_offset)) {
3274 mips_sb (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3275 } else {
3276 mips_load_const (code, mips_at, ins->inst_offset);
3277 mips_sb (code, mips_temp, mips_at, ins->inst_destbasereg);
3279 break;
3280 case OP_STOREI2_MEMBASE_IMM:
3281 mips_load_const (code, mips_temp, ins->inst_imm);
3282 if (mips_is_imm16 (ins->inst_offset)) {
3283 mips_sh (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3284 } else {
3285 mips_load_const (code, mips_at, ins->inst_offset);
3286 mips_sh (code, mips_temp, mips_at, ins->inst_destbasereg);
3288 break;
3289 case OP_STOREI8_MEMBASE_IMM:
3290 mips_load_const (code, mips_temp, ins->inst_imm);
3291 if (mips_is_imm16 (ins->inst_offset)) {
3292 mips_sd (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3293 } else {
3294 mips_load_const (code, mips_at, ins->inst_offset);
3295 mips_sd (code, mips_temp, mips_at, ins->inst_destbasereg);
3297 break;
3298 case OP_STORE_MEMBASE_IMM:
3299 case OP_STOREI4_MEMBASE_IMM:
3300 mips_load_const (code, mips_temp, ins->inst_imm);
3301 if (mips_is_imm16 (ins->inst_offset)) {
3302 mips_sw (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3303 } else {
3304 mips_load_const (code, mips_at, ins->inst_offset);
3305 mips_sw (code, mips_temp, mips_at, ins->inst_destbasereg);
3307 break;
3308 case OP_STOREI1_MEMBASE_REG:
3309 if (mips_is_imm16 (ins->inst_offset)) {
3310 mips_sb (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3311 } else {
3312 mips_load_const (code, mips_at, ins->inst_offset);
3313 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3314 mips_sb (code, ins->sreg1, mips_at, 0);
3316 break;
3317 case OP_STOREI2_MEMBASE_REG:
3318 if (mips_is_imm16 (ins->inst_offset)) {
3319 mips_sh (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3320 } else {
3321 mips_load_const (code, mips_at, ins->inst_offset);
3322 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3323 mips_sh (code, ins->sreg1, mips_at, 0);
3325 break;
3326 case OP_STORE_MEMBASE_REG:
3327 case OP_STOREI4_MEMBASE_REG:
3328 if (mips_is_imm16 (ins->inst_offset)) {
3329 mips_sw (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3330 } else {
3331 mips_load_const (code, mips_at, ins->inst_offset);
3332 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3333 mips_sw (code, ins->sreg1, mips_at, 0);
3335 break;
3336 case OP_STOREI8_MEMBASE_REG:
3337 if (mips_is_imm16 (ins->inst_offset)) {
3338 mips_sd (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3339 } else {
3340 mips_load_const (code, mips_at, ins->inst_offset);
3341 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3342 mips_sd (code, ins->sreg1, mips_at, 0);
3344 break;
3345 case OP_LOADU4_MEM:
3346 g_assert_not_reached ();
3347 //x86_mov_reg_imm (code, ins->dreg, ins->inst_p0);
3348 //x86_mov_reg_membase (code, ins->dreg, ins->dreg, 0, 4);
3349 break;
3350 case OP_LOADI8_MEMBASE:
3351 if (mips_is_imm16 (ins->inst_offset)) {
3352 mips_ld (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3353 } else {
3354 mips_load_const (code, mips_at, ins->inst_offset);
3355 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3356 mips_ld (code, ins->dreg, mips_at, 0);
3358 break;
3359 case OP_LOAD_MEMBASE:
3360 case OP_LOADI4_MEMBASE:
3361 case OP_LOADU4_MEMBASE:
3362 g_assert (ins->dreg != -1);
3363 if (mips_is_imm16 (ins->inst_offset)) {
3364 mips_lw (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3365 } else {
3366 mips_load_const (code, mips_at, ins->inst_offset);
3367 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3368 mips_lw (code, ins->dreg, mips_at, 0);
3370 break;
3371 case OP_LOADI1_MEMBASE:
3372 if (mips_is_imm16 (ins->inst_offset)) {
3373 mips_lb (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3374 } else {
3375 mips_load_const (code, mips_at, ins->inst_offset);
3376 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3377 mips_lb (code, ins->dreg, mips_at, 0);
3379 break;
3380 case OP_LOADU1_MEMBASE:
3381 if (mips_is_imm16 (ins->inst_offset)) {
3382 mips_lbu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3383 } else {
3384 mips_load_const (code, mips_at, ins->inst_offset);
3385 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3386 mips_lbu (code, ins->dreg, mips_at, 0);
3388 break;
3389 case OP_LOADI2_MEMBASE:
3390 if (mips_is_imm16 (ins->inst_offset)) {
3391 mips_lh (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3392 } else {
3393 mips_load_const (code, mips_at, ins->inst_offset);
3394 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3395 mips_lh (code, ins->dreg, mips_at, 0);
3397 break;
3398 case OP_LOADU2_MEMBASE:
3399 if (mips_is_imm16 (ins->inst_offset)) {
3400 mips_lhu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3401 } else {
3402 mips_load_const (code, mips_at, ins->inst_offset);
3403 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3404 mips_lhu (code, ins->dreg, mips_at, 0);
3406 break;
3407 case OP_ICONV_TO_I1:
3408 mips_sll (code, mips_at, ins->sreg1, 24);
3409 mips_sra (code, ins->dreg, mips_at, 24);
3410 break;
3411 case OP_ICONV_TO_I2:
3412 mips_sll (code, mips_at, ins->sreg1, 16);
3413 mips_sra (code, ins->dreg, mips_at, 16);
3414 break;
3415 case OP_ICONV_TO_U1:
3416 mips_andi (code, ins->dreg, ins->sreg1, 0xff);
3417 break;
3418 case OP_ICONV_TO_U2:
3419 mips_sll (code, mips_at, ins->sreg1, 16);
3420 mips_srl (code, ins->dreg, mips_at, 16);
3421 break;
3422 case OP_MIPS_SLT:
3423 mips_slt (code, ins->dreg, ins->sreg1, ins->sreg2);
3424 break;
3425 case OP_MIPS_SLTI:
3426 g_assert (mips_is_imm16 (ins->inst_imm));
3427 mips_slti (code, ins->dreg, ins->sreg1, ins->inst_imm);
3428 break;
3429 case OP_MIPS_SLTU:
3430 mips_sltu (code, ins->dreg, ins->sreg1, ins->sreg2);
3431 break;
3432 case OP_MIPS_SLTIU:
3433 g_assert (mips_is_imm16 (ins->inst_imm));
3434 mips_sltiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3435 break;
3436 case OP_BREAK:
3438 * gdb does not like encountering the hw breakpoint ins in the debugged code.
3439 * So instead of emitting a trap, we emit a call a C function and place a
3440 * breakpoint there.
3442 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_JIT_ICALL_ID, GUINT_TO_POINTER (MONO_JIT_ICALL_mono_break));
3443 mips_load (code, mips_t9, 0x1f1f1f1f);
3444 mips_jalr (code, mips_t9, mips_ra);
3445 mips_nop (code);
3446 break;
3447 case OP_IADD:
3448 mips_addu (code, ins->dreg, ins->sreg1, ins->sreg2);
3449 break;
3450 case OP_LADD:
3451 mips_daddu (code, ins->dreg, ins->sreg1, ins->sreg2);
3452 break;
3454 case OP_ADD_IMM:
3455 case OP_IADD_IMM:
3456 g_assert (mips_is_imm16 (ins->inst_imm));
3457 mips_addiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3458 break;
3459 case OP_LADD_IMM:
3460 g_assert (mips_is_imm16 (ins->inst_imm));
3461 mips_daddiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3462 break;
3464 case OP_ISUB:
3465 mips_subu (code, ins->dreg, ins->sreg1, ins->sreg2);
3466 break;
3467 case OP_LSUB:
3468 mips_dsubu (code, ins->dreg, ins->sreg1, ins->sreg2);
3469 break;
3471 case OP_ISUB_IMM:
3472 case OP_SUB_IMM:
3473 // we add the negated value
3474 g_assert (mips_is_imm16 (-ins->inst_imm));
3475 mips_addiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3476 break;
3478 case OP_LSUB_IMM:
3479 // we add the negated value
3480 g_assert (mips_is_imm16 (-ins->inst_imm));
3481 mips_daddiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3482 break;
3484 case OP_IAND:
3485 case OP_LAND:
3486 mips_and (code, ins->dreg, ins->sreg1, ins->sreg2);
3487 break;
3489 case OP_AND_IMM:
3490 case OP_IAND_IMM:
3491 case OP_LAND_IMM:
3492 g_assert (!(ins->inst_imm & 0xffff0000));
3493 mips_andi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3494 break;
3496 case OP_IDIV:
3497 case OP_IREM: {
3498 guint32 *divisor_is_m1;
3499 guint32 *dividend_is_minvalue;
3500 guint32 *divisor_is_zero;
3502 mips_load_const (code, mips_at, -1);
3503 divisor_is_m1 = (guint32 *)(void *)code;
3504 mips_bne (code, ins->sreg2, mips_at, 0);
3505 mips_lui (code, mips_at, mips_zero, 0x8000);
3506 dividend_is_minvalue = (guint32 *)(void *)code;
3507 mips_bne (code, ins->sreg1, mips_at, 0);
3508 mips_nop (code);
3510 /* Divide Int32.MinValue by -1 -- throw exception */
3511 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3513 mips_patch (divisor_is_m1, (guint32)code);
3514 mips_patch (dividend_is_minvalue, (guint32)code);
3516 /* Put divide in branch delay slot (NOT YET) */
3517 divisor_is_zero = (guint32 *)(void *)code;
3518 mips_bne (code, ins->sreg2, mips_zero, 0);
3519 mips_nop (code);
3521 /* Divide by zero -- throw exception */
3522 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3524 mips_patch (divisor_is_zero, (guint32)code);
3525 mips_div (code, ins->sreg1, ins->sreg2);
3526 if (ins->opcode == OP_IDIV)
3527 mips_mflo (code, ins->dreg);
3528 else
3529 mips_mfhi (code, ins->dreg);
3530 break;
3532 case OP_IDIV_UN:
3533 case OP_IREM_UN: {
3534 guint32 *divisor_is_zero = (guint32 *)(void *)code;
3536 /* Put divide in branch delay slot (NOT YET) */
3537 mips_bne (code, ins->sreg2, mips_zero, 0);
3538 mips_nop (code);
3540 /* Divide by zero -- throw exception */
3541 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3543 mips_patch (divisor_is_zero, (guint32)code);
3544 mips_divu (code, ins->sreg1, ins->sreg2);
3545 if (ins->opcode == OP_IDIV_UN)
3546 mips_mflo (code, ins->dreg);
3547 else
3548 mips_mfhi (code, ins->dreg);
3549 break;
3551 case OP_DIV_IMM:
3552 g_assert_not_reached ();
3553 #if 0
3554 ppc_load (code, ppc_r12, ins->inst_imm);
3555 ppc_divwod (code, ins->dreg, ins->sreg1, ppc_r12);
3556 ppc_mfspr (code, ppc_r0, ppc_xer);
3557 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3558 /* FIXME: use OverflowException for 0x80000000/-1 */
3559 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3560 #endif
3561 g_assert_not_reached();
3562 break;
3563 case OP_REM_IMM:
3564 g_assert_not_reached ();
3565 case OP_IOR:
3566 mips_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3567 break;
3568 case OP_OR_IMM:
3569 case OP_IOR_IMM:
3570 g_assert (!(ins->inst_imm & 0xffff0000));
3571 mips_ori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3572 break;
3573 case OP_IXOR:
3574 mips_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3575 break;
3576 case OP_XOR_IMM:
3577 case OP_IXOR_IMM:
3578 /* unsigned 16-bit immediate */
3579 g_assert (!(ins->inst_imm & 0xffff0000));
3580 mips_xori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3581 break;
3582 case OP_ISHL:
3583 mips_sllv (code, ins->dreg, ins->sreg1, ins->sreg2);
3584 break;
3585 case OP_SHL_IMM:
3586 case OP_ISHL_IMM:
3587 mips_sll (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3588 break;
3589 case OP_ISHR:
3590 mips_srav (code, ins->dreg, ins->sreg1, ins->sreg2);
3591 break;
3592 case OP_LSHR:
3593 mips_dsrav (code, ins->dreg, ins->sreg1, ins->sreg2);
3594 break;
3595 case OP_SHR_IMM:
3596 case OP_ISHR_IMM:
3597 mips_sra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3598 break;
3599 case OP_LSHR_IMM:
3600 mips_dsra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3601 break;
3602 case OP_SHR_UN_IMM:
3603 case OP_ISHR_UN_IMM:
3604 mips_srl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3605 break;
3606 case OP_LSHR_UN_IMM:
3607 mips_dsrl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3608 break;
3609 case OP_ISHR_UN:
3610 mips_srlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3611 break;
3612 case OP_LSHR_UN:
3613 mips_dsrlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3614 break;
3615 case OP_INOT:
3616 case OP_LNOT:
3617 mips_nor (code, ins->dreg, mips_zero, ins->sreg1);
3618 break;
3619 case OP_INEG:
3620 mips_subu (code, ins->dreg, mips_zero, ins->sreg1);
3621 break;
3622 case OP_LNEG:
3623 mips_dsubu (code, ins->dreg, mips_zero, ins->sreg1);
3624 break;
3625 case OP_IMUL:
3626 #if USE_MUL
3627 mips_mul (code, ins->dreg, ins->sreg1, ins->sreg2);
3628 #else
3629 mips_mult (code, ins->sreg1, ins->sreg2);
3630 mips_mflo (code, ins->dreg);
3631 mips_nop (code);
3632 mips_nop (code);
3633 #endif
3634 break;
3635 #if SIZEOF_REGISTER == 8
3636 case OP_LMUL:
3637 mips_dmult (code, ins->sreg1, ins->sreg2);
3638 mips_mflo (code, ins->dreg);
3639 break;
3640 #endif
3641 case OP_IMUL_OVF: {
3642 guint32 *patch;
3643 mips_mult (code, ins->sreg1, ins->sreg2);
3644 mips_mflo (code, ins->dreg);
3645 mips_mfhi (code, mips_at);
3646 mips_nop (code);
3647 mips_nop (code);
3648 mips_sra (code, mips_temp, ins->dreg, 31);
3649 patch = (guint32 *)(void *)code;
3650 mips_beq (code, mips_temp, mips_at, 0);
3651 mips_nop (code);
3652 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3653 mips_patch (patch, (guint32)code);
3654 break;
3656 case OP_IMUL_OVF_UN: {
3657 guint32 *patch;
3658 mips_mult (code, ins->sreg1, ins->sreg2);
3659 mips_mflo (code, ins->dreg);
3660 mips_mfhi (code, mips_at);
3661 mips_nop (code);
3662 mips_nop (code);
3663 patch = (guint32 *)(void *)code;
3664 mips_beq (code, mips_at, mips_zero, 0);
3665 mips_nop (code);
3666 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3667 mips_patch (patch, (guint32)code);
3668 break;
3670 case OP_ICONST:
3671 mips_load_const (code, ins->dreg, ins->inst_c0);
3672 break;
3673 #if SIZEOF_REGISTER == 8
3674 case OP_I8CONST:
3675 mips_load_const (code, ins->dreg, ins->inst_c0);
3676 break;
3677 #endif
3678 case OP_AOTCONST:
3679 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3680 mips_load (code, ins->dreg, 0);
3681 break;
3683 case OP_MIPS_MTC1S:
3684 mips_mtc1 (code, ins->dreg, ins->sreg1);
3685 break;
3686 case OP_MIPS_MTC1S_2:
3687 mips_mtc1 (code, ins->dreg, ins->sreg1);
3688 mips_mtc1 (code, ins->dreg+1, ins->sreg2);
3689 break;
3690 case OP_MIPS_MFC1S:
3691 mips_mfc1 (code, ins->dreg, ins->sreg1);
3692 break;
3693 case OP_MIPS_MTC1D:
3694 mips_dmtc1 (code, ins->dreg, ins->sreg1);
3695 break;
3696 case OP_MIPS_MFC1D:
3697 #if 0
3698 mips_dmfc1 (code, ins->dreg, ins->sreg1);
3699 #else
3700 mips_mfc1 (code, ins->dreg, ins->sreg1 + ls_word_idx);
3701 mips_mfc1 (code, ins->dreg+1, ins->sreg1 + ms_word_idx);
3702 #endif
3703 break;
3705 case OP_ICONV_TO_I4:
3706 case OP_ICONV_TO_U4:
3707 case OP_MOVE:
3708 if (ins->dreg != ins->sreg1)
3709 MIPS_MOVE (code, ins->dreg, ins->sreg1);
3710 break;
3711 #if SIZEOF_REGISTER == 8
3712 case OP_ZEXT_I4:
3713 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3714 mips_dsrl (code, ins->dreg, ins->dreg, 32);
3715 break;
3716 case OP_SEXT_I4:
3717 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3718 mips_dsra (code, ins->dreg, ins->dreg, 32);
3719 break;
3720 #endif
3721 case OP_SETLRET: {
3722 int lsreg = mips_v0 + ls_word_idx;
3723 int msreg = mips_v0 + ms_word_idx;
3725 /* Get sreg1 into lsreg, sreg2 into msreg */
3727 if (ins->sreg1 == msreg) {
3728 if (ins->sreg1 != mips_at)
3729 MIPS_MOVE (code, mips_at, ins->sreg1);
3730 if (ins->sreg2 != msreg)
3731 MIPS_MOVE (code, msreg, ins->sreg2);
3732 MIPS_MOVE (code, lsreg, mips_at);
3734 else {
3735 if (ins->sreg2 != msreg)
3736 MIPS_MOVE (code, msreg, ins->sreg2);
3737 if (ins->sreg1 != lsreg)
3738 MIPS_MOVE (code, lsreg, ins->sreg1);
3740 break;
3742 case OP_FMOVE:
3743 if (ins->dreg != ins->sreg1) {
3744 mips_fmovd (code, ins->dreg, ins->sreg1);
3746 break;
3747 case OP_MOVE_F_TO_I4:
3748 mips_cvtsd (code, mips_ftemp, ins->sreg1);
3749 mips_mfc1 (code, ins->dreg, mips_ftemp);
3750 break;
3751 case OP_MOVE_I4_TO_F:
3752 mips_mtc1 (code, ins->dreg, ins->sreg1);
3753 mips_cvtds (code, ins->dreg, ins->dreg);
3754 break;
3755 case OP_MIPS_CVTSD:
3756 /* Convert from double to float and leave it there */
3757 mips_cvtsd (code, ins->dreg, ins->sreg1);
3758 break;
3759 case OP_FCONV_TO_R4:
3760 #if 0
3761 mips_cvtsd (code, ins->dreg, ins->sreg1);
3762 #else
3763 /* Just a move, no precision change */
3764 if (ins->dreg != ins->sreg1) {
3765 mips_fmovd (code, ins->dreg, ins->sreg1);
3767 #endif
3768 break;
3769 case OP_CHECK_THIS:
3770 /* ensure ins->sreg1 is not NULL */
3771 mips_lw (code, mips_zero, ins->sreg1, 0);
3772 break;
3773 case OP_ARGLIST: {
3774 g_assert (mips_is_imm16 (cfg->sig_cookie));
3775 mips_lw (code, mips_at, cfg->frame_reg, cfg->sig_cookie);
3776 mips_sw (code, mips_at, ins->sreg1, 0);
3777 break;
3779 case OP_FCALL:
3780 case OP_LCALL:
3781 case OP_VCALL:
3782 case OP_VCALL2:
3783 case OP_VOIDCALL:
3784 case OP_CALL:
3785 case OP_FCALL_REG:
3786 case OP_LCALL_REG:
3787 case OP_VCALL_REG:
3788 case OP_VCALL2_REG:
3789 case OP_VOIDCALL_REG:
3790 case OP_CALL_REG:
3791 case OP_FCALL_MEMBASE:
3792 case OP_LCALL_MEMBASE:
3793 case OP_VCALL_MEMBASE:
3794 case OP_VCALL2_MEMBASE:
3795 case OP_VOIDCALL_MEMBASE:
3796 case OP_CALL_MEMBASE:
3797 call = (MonoCallInst*)ins;
3798 switch (ins->opcode) {
3799 case OP_FCALL:
3800 case OP_LCALL:
3801 case OP_VCALL:
3802 case OP_VCALL2:
3803 case OP_VOIDCALL:
3804 case OP_CALL:
3805 mono_call_add_patch_info (cfg, call, offset);
3806 if (ins->flags & MONO_INST_HAS_METHOD) {
3807 mips_load (code, mips_t9, call->method);
3809 else {
3810 mips_load (code, mips_t9, call->fptr);
3812 mips_jalr (code, mips_t9, mips_ra);
3813 mips_nop (code);
3814 break;
3815 case OP_FCALL_REG:
3816 case OP_LCALL_REG:
3817 case OP_VCALL_REG:
3818 case OP_VCALL2_REG:
3819 case OP_VOIDCALL_REG:
3820 case OP_CALL_REG:
3821 MIPS_MOVE (code, mips_t9, ins->sreg1);
3822 mips_jalr (code, mips_t9, mips_ra);
3823 mips_nop (code);
3824 break;
3825 case OP_FCALL_MEMBASE:
3826 case OP_LCALL_MEMBASE:
3827 case OP_VCALL_MEMBASE:
3828 case OP_VCALL2_MEMBASE:
3829 case OP_VOIDCALL_MEMBASE:
3830 case OP_CALL_MEMBASE:
3831 mips_lw (code, mips_t9, ins->sreg1, ins->inst_offset);
3832 mips_jalr (code, mips_t9, mips_ra);
3833 mips_nop (code);
3834 break;
3836 #if PROMOTE_R4_TO_R8
3837 /* returned an FP R4 (single), promote to R8 (double) in place */
3838 switch (ins->opcode) {
3839 case OP_FCALL:
3840 case OP_FCALL_REG:
3841 case OP_FCALL_MEMBASE:
3842 if (call->signature->ret->type == MONO_TYPE_R4)
3843 mips_cvtds (code, mips_f0, mips_f0);
3844 break;
3845 default:
3846 break;
3848 #endif
3849 break;
3850 case OP_LOCALLOC: {
3851 int area_offset = cfg->param_area;
3853 /* Round up ins->sreg1, mips_at ends up holding size */
3854 mips_addiu (code, mips_at, ins->sreg1, 31);
3855 mips_addiu (code, mips_temp, mips_zero, ~31);
3856 mips_and (code, mips_at, mips_at, mips_temp);
3858 mips_subu (code, mips_sp, mips_sp, mips_at);
3859 g_assert (mips_is_imm16 (area_offset));
3860 mips_addiu (code, ins->dreg, mips_sp, area_offset);
3862 if (ins->flags & MONO_INST_INIT) {
3863 guint32 *buf;
3865 buf = (guint32*)(void*)code;
3866 mips_beq (code, mips_at, mips_zero, 0);
3867 mips_nop (code);
3869 mips_move (code, mips_temp, ins->dreg);
3870 mips_sb (code, mips_zero, mips_temp, 0);
3871 mips_addiu (code, mips_at, mips_at, -1);
3872 mips_bne (code, mips_at, mips_zero, -3);
3873 mips_addiu (code, mips_temp, mips_temp, 1);
3875 mips_patch (buf, (guint32)code);
3877 break;
3879 case OP_THROW: {
3880 gpointer addr = mono_arch_get_throw_exception(NULL, FALSE);
3881 mips_move (code, mips_a0, ins->sreg1);
3882 mips_call (code, mips_t9, addr);
3883 mips_break (code, 0xfc);
3884 break;
3886 case OP_RETHROW: {
3887 gpointer addr = mono_arch_get_rethrow_exception(NULL, FALSE);
3888 mips_move (code, mips_a0, ins->sreg1);
3889 mips_call (code, mips_t9, addr);
3890 mips_break (code, 0xfb);
3891 break;
3893 case OP_START_HANDLER: {
3895 * The START_HANDLER instruction marks the beginning of
3896 * a handler block. It is called using a call
3897 * instruction, so mips_ra contains the return address.
3898 * Since the handler executes in the same stack frame
3899 * as the method itself, we can't use save/restore to
3900 * save the return address. Instead, we save it into
3901 * a dedicated variable.
3903 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3904 g_assert (spvar->inst_basereg != mips_sp);
3905 code = emit_reserve_param_area (cfg, code);
3907 if (mips_is_imm16 (spvar->inst_offset)) {
3908 mips_sw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
3909 } else {
3910 mips_load_const (code, mips_at, spvar->inst_offset);
3911 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
3912 mips_sw (code, mips_ra, mips_at, 0);
3914 break;
3916 case OP_ENDFILTER: {
3917 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3918 g_assert (spvar->inst_basereg != mips_sp);
3919 code = emit_unreserve_param_area (cfg, code);
3921 if (ins->sreg1 != mips_v0)
3922 MIPS_MOVE (code, mips_v0, ins->sreg1);
3923 if (mips_is_imm16 (spvar->inst_offset)) {
3924 mips_lw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
3925 } else {
3926 mips_load_const (code, mips_at, spvar->inst_offset);
3927 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
3928 mips_lw (code, mips_ra, mips_at, 0);
3930 mips_jr (code, mips_ra);
3931 mips_nop (code);
3932 break;
3934 case OP_ENDFINALLY: {
3935 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3936 g_assert (spvar->inst_basereg != mips_sp);
3937 code = emit_unreserve_param_area (cfg, code);
3938 mips_lw (code, mips_t9, spvar->inst_basereg, spvar->inst_offset);
3939 mips_jalr (code, mips_t9, mips_ra);
3940 mips_nop (code);
3941 break;
3943 case OP_CALL_HANDLER:
3944 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3945 mips_lui (code, mips_t9, mips_zero, 0);
3946 mips_addiu (code, mips_t9, mips_t9, 0);
3947 mips_jalr (code, mips_t9, mips_ra);
3948 mips_nop (code);
3949 /*FIXME should it be before the NOP or not? Does MIPS has a delay slot like sparc?*/
3950 for (GList *tmp = ins->inst_eh_blocks; tmp != bb->clause_holes; tmp = tmp->prev)
3951 mono_cfg_add_try_hole (cfg, ((MonoLeaveClause *) tmp->data)->clause, code, bb);
3952 break;
3953 case OP_LABEL:
3954 ins->inst_c0 = code - cfg->native_code;
3955 break;
3956 case OP_BR:
3957 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3958 if (cfg->arch.long_branch) {
3959 mips_lui (code, mips_at, mips_zero, 0);
3960 mips_addiu (code, mips_at, mips_at, 0);
3961 mips_jr (code, mips_at);
3962 mips_nop (code);
3964 else {
3965 mips_beq (code, mips_zero, mips_zero, 0);
3966 mips_nop (code);
3968 break;
3969 case OP_BR_REG:
3970 mips_jr (code, ins->sreg1);
3971 mips_nop (code);
3972 break;
3973 case OP_SWITCH: {
3974 int i;
3976 max_len += 4 * GPOINTER_TO_INT (ins->klass);
3977 code = realloc_code (cfg, max_len);
3979 g_assert (ins->sreg1 != -1);
3980 mips_sll (code, mips_at, ins->sreg1, 2);
3981 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS))
3982 MIPS_MOVE (code, mips_t8, mips_ra);
3983 mips_bgezal (code, mips_zero, 1); /* bal */
3984 mips_nop (code);
3985 mips_addu (code, mips_t9, mips_ra, mips_at);
3986 /* Table is 16 or 20 bytes from target of bal above */
3987 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS)) {
3988 MIPS_MOVE (code, mips_ra, mips_t8);
3989 mips_lw (code, mips_t9, mips_t9, 20);
3991 else
3992 mips_lw (code, mips_t9, mips_t9, 16);
3993 mips_jalr (code, mips_t9, mips_t8);
3994 mips_nop (code);
3995 for (i = 0; i < GPOINTER_TO_INT (ins->klass); ++i)
3996 mips_emit32 (code, 0xfefefefe);
3997 break;
3999 case OP_CEQ:
4000 case OP_ICEQ:
4001 mips_addiu (code, ins->dreg, mips_zero, 1);
4002 mips_beq (code, mips_at, mips_zero, 2);
4003 mips_nop (code);
4004 MIPS_MOVE (code, ins->dreg, mips_zero);
4005 break;
4006 case OP_CLT:
4007 case OP_CLT_UN:
4008 case OP_ICLT:
4009 case OP_ICLT_UN:
4010 mips_addiu (code, ins->dreg, mips_zero, 1);
4011 mips_bltz (code, mips_at, 2);
4012 mips_nop (code);
4013 MIPS_MOVE (code, ins->dreg, mips_zero);
4014 break;
4015 case OP_CGT:
4016 case OP_CGT_UN:
4017 case OP_ICGT:
4018 case OP_ICGT_UN:
4019 mips_addiu (code, ins->dreg, mips_zero, 1);
4020 mips_bgtz (code, mips_at, 2);
4021 mips_nop (code);
4022 MIPS_MOVE (code, ins->dreg, mips_zero);
4023 break;
4025 case OP_MIPS_COND_EXC_EQ:
4026 case OP_MIPS_COND_EXC_GE:
4027 case OP_MIPS_COND_EXC_GT:
4028 case OP_MIPS_COND_EXC_LE:
4029 case OP_MIPS_COND_EXC_LT:
4030 case OP_MIPS_COND_EXC_NE_UN:
4031 case OP_MIPS_COND_EXC_GE_UN:
4032 case OP_MIPS_COND_EXC_GT_UN:
4033 case OP_MIPS_COND_EXC_LE_UN:
4034 case OP_MIPS_COND_EXC_LT_UN:
4036 case OP_MIPS_COND_EXC_OV:
4037 case OP_MIPS_COND_EXC_NO:
4038 case OP_MIPS_COND_EXC_C:
4039 case OP_MIPS_COND_EXC_NC:
4041 case OP_MIPS_COND_EXC_IEQ:
4042 case OP_MIPS_COND_EXC_IGE:
4043 case OP_MIPS_COND_EXC_IGT:
4044 case OP_MIPS_COND_EXC_ILE:
4045 case OP_MIPS_COND_EXC_ILT:
4046 case OP_MIPS_COND_EXC_INE_UN:
4047 case OP_MIPS_COND_EXC_IGE_UN:
4048 case OP_MIPS_COND_EXC_IGT_UN:
4049 case OP_MIPS_COND_EXC_ILE_UN:
4050 case OP_MIPS_COND_EXC_ILT_UN:
4052 case OP_MIPS_COND_EXC_IOV:
4053 case OP_MIPS_COND_EXC_INO:
4054 case OP_MIPS_COND_EXC_IC:
4055 case OP_MIPS_COND_EXC_INC: {
4056 guint32 *skip;
4057 guint32 *throw;
4059 /* If the condition is true, raise the exception */
4061 /* need to reverse test to skip around exception raising */
4063 /* For the moment, branch around a branch to avoid reversing
4064 the tests. */
4066 /* Remember, an unpatched branch to 0 branches to the delay slot */
4067 switch (ins->opcode) {
4068 case OP_MIPS_COND_EXC_EQ:
4069 throw = (guint32 *)(void *)code;
4070 mips_beq (code, ins->sreg1, ins->sreg2, 0);
4071 mips_nop (code);
4072 break;
4074 case OP_MIPS_COND_EXC_NE_UN:
4075 throw = (guint32 *)(void *)code;
4076 mips_bne (code, ins->sreg1, ins->sreg2, 0);
4077 mips_nop (code);
4078 break;
4080 case OP_MIPS_COND_EXC_LE_UN:
4081 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
4082 throw = (guint32 *)(void *)code;
4083 mips_beq (code, mips_at, mips_zero, 0);
4084 mips_nop (code);
4085 break;
4087 case OP_MIPS_COND_EXC_GT:
4088 mips_slt (code, mips_at, ins->sreg2, ins->sreg1);
4089 throw = (guint32 *)(void *)code;
4090 mips_bne (code, mips_at, mips_zero, 0);
4091 mips_nop (code);
4092 break;
4094 case OP_MIPS_COND_EXC_GT_UN:
4095 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
4096 throw = (guint32 *)(void *)code;
4097 mips_bne (code, mips_at, mips_zero, 0);
4098 mips_nop (code);
4099 break;
4101 case OP_MIPS_COND_EXC_LT:
4102 mips_slt (code, mips_at, ins->sreg1, ins->sreg2);
4103 throw = (guint32 *)(void *)code;
4104 mips_bne (code, mips_at, mips_zero, 0);
4105 mips_nop (code);
4106 break;
4108 case OP_MIPS_COND_EXC_LT_UN:
4109 mips_sltu (code, mips_at, ins->sreg1, ins->sreg2);
4110 throw = (guint32 *)(void *)code;
4111 mips_bne (code, mips_at, mips_zero, 0);
4112 mips_nop (code);
4113 break;
4115 default:
4116 /* Not yet implemented */
4117 g_warning ("NYI conditional exception %s\n", mono_inst_name (ins->opcode));
4118 g_assert_not_reached ();
4120 skip = (guint32 *)(void *)code;
4121 mips_beq (code, mips_zero, mips_zero, 0);
4122 mips_nop (code);
4123 mips_patch (throw, (guint32)code);
4124 code = mips_emit_exc_by_name (code, ins->inst_p1);
4125 mips_patch (skip, (guint32)code);
4126 cfg->bb_exit->max_offset += 24;
4127 break;
4129 case OP_MIPS_BEQ:
4130 case OP_MIPS_BNE:
4131 case OP_MIPS_BGEZ:
4132 case OP_MIPS_BGTZ:
4133 case OP_MIPS_BLEZ:
4134 case OP_MIPS_BLTZ:
4135 code = mips_emit_cond_branch (cfg, code, ins->opcode, ins);
4136 break;
4138 /* floating point opcodes */
4139 case OP_R8CONST:
4140 #if 0
4141 if (((guint32)ins->inst_p0) & (1 << 15))
4142 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4143 else
4144 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4145 mips_ldc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4146 #else
4147 mips_load_const (code, mips_at, ins->inst_p0);
4148 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4149 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4150 #endif
4151 break;
4152 case OP_R4CONST:
4153 if (((guint32)ins->inst_p0) & (1 << 15))
4154 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4155 else
4156 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4157 mips_lwc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4158 #if PROMOTE_R4_TO_R8
4159 mips_cvtds (code, ins->dreg, ins->dreg);
4160 #endif
4161 break;
4162 case OP_STORER8_MEMBASE_REG:
4163 if (mips_is_imm16 (ins->inst_offset)) {
4164 #if _MIPS_SIM == _ABIO32
4165 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset + ls_word_offset);
4166 mips_swc1 (code, ins->sreg1+1, ins->inst_destbasereg, ins->inst_offset + ms_word_offset);
4167 #elif _MIPS_SIM == _ABIN32
4168 mips_sdc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4169 #endif
4170 } else {
4171 mips_load_const (code, mips_at, ins->inst_offset);
4172 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
4173 mips_swc1 (code, ins->sreg1, mips_at, ls_word_offset);
4174 mips_swc1 (code, ins->sreg1+1, mips_at, ms_word_offset);
4176 break;
4177 case OP_LOADR8_MEMBASE:
4178 if (mips_is_imm16 (ins->inst_offset)) {
4179 #if _MIPS_SIM == _ABIO32
4180 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset + ls_word_offset);
4181 mips_lwc1 (code, ins->dreg+1, ins->inst_basereg, ins->inst_offset + ms_word_offset);
4182 #elif _MIPS_SIM == _ABIN32
4183 mips_ldc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4184 #endif
4185 } else {
4186 mips_load_const (code, mips_at, ins->inst_offset);
4187 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
4188 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4189 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4191 break;
4192 case OP_STORER4_MEMBASE_REG:
4193 g_assert (mips_is_imm16 (ins->inst_offset));
4194 #if PROMOTE_R4_TO_R8
4195 /* Need to convert ins->sreg1 to single-precision first */
4196 mips_cvtsd (code, mips_ftemp, ins->sreg1);
4197 mips_swc1 (code, mips_ftemp, ins->inst_destbasereg, ins->inst_offset);
4198 #else
4199 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4200 #endif
4201 break;
4202 case OP_MIPS_LWC1:
4203 g_assert (mips_is_imm16 (ins->inst_offset));
4204 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4205 break;
4206 case OP_LOADR4_MEMBASE:
4207 g_assert (mips_is_imm16 (ins->inst_offset));
4208 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4209 #if PROMOTE_R4_TO_R8
4210 /* Convert to double precision in place */
4211 mips_cvtds (code, ins->dreg, ins->dreg);
4212 #endif
4213 break;
4214 case OP_LOADR4_MEMINDEX:
4215 mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4216 mips_lwc1 (code, ins->dreg, mips_at, 0);
4217 break;
4218 case OP_LOADR8_MEMINDEX:
4219 mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4220 #if _MIPS_SIM == _ABIO32
4221 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4222 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4223 #elif _MIPS_SIM == _ABIN32
4224 mips_ldc1 (code, ins->dreg, mips_at, 0);
4225 #endif
4226 break;
4227 case OP_STORER4_MEMINDEX:
4228 mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4229 #if PROMOTE_R4_TO_R8
4230 /* Need to convert ins->sreg1 to single-precision first */
4231 mips_cvtsd (code, mips_ftemp, ins->sreg1);
4232 mips_swc1 (code, mips_ftemp, mips_at, 0);
4233 #else
4234 mips_swc1 (code, ins->sreg1, mips_at, 0);
4235 #endif
4236 break;
4237 case OP_STORER8_MEMINDEX:
4238 mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4239 #if _MIPS_SIM == _ABIO32
4240 mips_swc1 (code, ins->sreg1, mips_at, ls_word_offset);
4241 mips_swc1 (code, ins->sreg1+1, mips_at, ms_word_offset);
4242 #elif _MIPS_SIM == _ABIN32
4243 mips_sdc1 (code, ins->sreg1, mips_at, 0);
4244 #endif
4245 break;
4246 case OP_ICONV_TO_R_UN: {
4247 static const guint64 adjust_val = 0x41F0000000000000ULL;
4249 /* convert unsigned int to double */
4250 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4251 mips_bgez (code, ins->sreg1, 5);
4252 mips_cvtdw (code, ins->dreg, mips_ftemp);
4254 mips_load (code, mips_at, (guint32) &adjust_val);
4255 mips_ldc1 (code, mips_ftemp, mips_at, 0);
4256 mips_faddd (code, ins->dreg, ins->dreg, mips_ftemp);
4257 /* target is here */
4258 break;
4260 case OP_ICONV_TO_R4:
4261 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4262 mips_cvtsw (code, ins->dreg, mips_ftemp);
4263 mips_cvtds (code, ins->dreg, ins->dreg);
4264 break;
4265 case OP_ICONV_TO_R8:
4266 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4267 mips_cvtdw (code, ins->dreg, mips_ftemp);
4268 break;
4269 case OP_FCONV_TO_I1:
4270 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4271 break;
4272 case OP_FCONV_TO_U1:
4273 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4274 break;
4275 case OP_FCONV_TO_I2:
4276 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4277 break;
4278 case OP_FCONV_TO_U2:
4279 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4280 break;
4281 case OP_FCONV_TO_I4:
4282 case OP_FCONV_TO_I:
4283 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4284 break;
4285 case OP_FCONV_TO_U4:
4286 case OP_FCONV_TO_U:
4287 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4288 break;
4289 case OP_SQRT:
4290 mips_fsqrtd (code, ins->dreg, ins->sreg1);
4291 break;
4292 case OP_FADD:
4293 mips_faddd (code, ins->dreg, ins->sreg1, ins->sreg2);
4294 break;
4295 case OP_FSUB:
4296 mips_fsubd (code, ins->dreg, ins->sreg1, ins->sreg2);
4297 break;
4298 case OP_FMUL:
4299 mips_fmuld (code, ins->dreg, ins->sreg1, ins->sreg2);
4300 break;
4301 case OP_FDIV:
4302 mips_fdivd (code, ins->dreg, ins->sreg1, ins->sreg2);
4303 break;
4304 case OP_FNEG:
4305 mips_fnegd (code, ins->dreg, ins->sreg1);
4306 break;
4307 case OP_FCEQ:
4308 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
4309 mips_addiu (code, ins->dreg, mips_zero, 1);
4310 mips_fbtrue (code, 2);
4311 mips_nop (code);
4312 MIPS_MOVE (code, ins->dreg, mips_zero);
4313 break;
4314 case OP_FCLT:
4315 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
4316 mips_addiu (code, ins->dreg, mips_zero, 1);
4317 mips_fbtrue (code, 2);
4318 mips_nop (code);
4319 MIPS_MOVE (code, ins->dreg, mips_zero);
4320 break;
4321 case OP_FCLT_UN:
4322 /* Less than, or Unordered */
4323 mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
4324 mips_addiu (code, ins->dreg, mips_zero, 1);
4325 mips_fbtrue (code, 2);
4326 mips_nop (code);
4327 MIPS_MOVE (code, ins->dreg, mips_zero);
4328 break;
4329 case OP_FCGT:
4330 mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
4331 MIPS_MOVE (code, ins->dreg, mips_zero);
4332 mips_fbtrue (code, 2);
4333 mips_nop (code);
4334 mips_addiu (code, ins->dreg, mips_zero, 1);
4335 break;
4336 case OP_FCGT_UN:
4337 /* Greater than, or Unordered */
4338 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
4339 MIPS_MOVE (code, ins->dreg, mips_zero);
4340 mips_fbtrue (code, 2);
4341 mips_nop (code);
4342 mips_addiu (code, ins->dreg, mips_zero, 1);
4343 break;
4344 case OP_MIPS_FBEQ:
4345 case OP_MIPS_FBNE:
4346 case OP_MIPS_FBLT:
4347 case OP_MIPS_FBLT_UN:
4348 case OP_MIPS_FBGT:
4349 case OP_MIPS_FBGT_UN:
4350 case OP_MIPS_FBGE:
4351 case OP_MIPS_FBGE_UN:
4352 case OP_MIPS_FBLE:
4353 case OP_MIPS_FBLE_UN: {
4354 int cond = 0;
4355 gboolean is_true = TRUE, is_ordered = FALSE;
4356 guint32 *buf = NULL;
4358 switch (ins->opcode) {
4359 case OP_MIPS_FBEQ:
4360 cond = MIPS_FPU_EQ;
4361 is_true = TRUE;
4362 break;
4363 case OP_MIPS_FBNE:
4364 cond = MIPS_FPU_EQ;
4365 is_true = FALSE;
4366 break;
4367 case OP_MIPS_FBLT:
4368 cond = MIPS_FPU_LT;
4369 is_true = TRUE;
4370 is_ordered = TRUE;
4371 break;
4372 case OP_MIPS_FBLT_UN:
4373 cond = MIPS_FPU_ULT;
4374 is_true = TRUE;
4375 break;
4376 case OP_MIPS_FBGT:
4377 cond = MIPS_FPU_LE;
4378 is_true = FALSE;
4379 is_ordered = TRUE;
4380 break;
4381 case OP_MIPS_FBGT_UN:
4382 cond = MIPS_FPU_OLE;
4383 is_true = FALSE;
4384 break;
4385 case OP_MIPS_FBGE:
4386 cond = MIPS_FPU_LT;
4387 is_true = FALSE;
4388 is_ordered = TRUE;
4389 break;
4390 case OP_MIPS_FBGE_UN:
4391 cond = MIPS_FPU_OLT;
4392 is_true = FALSE;
4393 break;
4394 case OP_MIPS_FBLE:
4395 cond = MIPS_FPU_OLE;
4396 is_true = TRUE;
4397 is_ordered = TRUE;
4398 break;
4399 case OP_MIPS_FBLE_UN:
4400 cond = MIPS_FPU_ULE;
4401 is_true = TRUE;
4402 break;
4403 default:
4404 g_assert_not_reached ();
4407 if (is_ordered) {
4408 /* Skip the check if unordered */
4409 mips_fcmpd (code, MIPS_FPU_UN, ins->sreg1, ins->sreg2);
4410 mips_nop (code);
4411 buf = (guint32*)code;
4412 mips_fbtrue (code, 0);
4413 mips_nop (code);
4416 mips_fcmpd (code, cond, ins->sreg1, ins->sreg2);
4417 mips_nop (code);
4418 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4419 if (is_true)
4420 mips_fbtrue (code, 0);
4421 else
4422 mips_fbfalse (code, 0);
4423 mips_nop (code);
4425 if (is_ordered)
4426 mips_patch (buf, (guint32)code);
4427 break;
4429 case OP_CKFINITE: {
4430 guint32 *branch_patch;
4432 mips_mfc1 (code, mips_at, ins->sreg1+1);
4433 mips_srl (code, mips_at, mips_at, 16+4);
4434 mips_andi (code, mips_at, mips_at, 2047);
4435 mips_addiu (code, mips_at, mips_at, -2047);
4437 branch_patch = (guint32 *)(void *)code;
4438 mips_bne (code, mips_at, mips_zero, 0);
4439 mips_nop (code);
4441 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
4442 mips_patch (branch_patch, (guint32)code);
4443 mips_fmovd (code, ins->dreg, ins->sreg1);
4444 break;
4446 case OP_JUMP_TABLE:
4447 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
4448 mips_load (code, ins->dreg, 0x0f0f0f0f);
4449 break;
4450 case OP_LIVERANGE_START: {
4451 if (cfg->verbose_level > 1)
4452 printf ("R%d START=0x%x\n", MONO_VARINFO (cfg, ins->inst_c0)->vreg, (int)(code - cfg->native_code));
4453 MONO_VARINFO (cfg, ins->inst_c0)->live_range_start = code - cfg->native_code;
4454 break;
4456 case OP_LIVERANGE_END: {
4457 if (cfg->verbose_level > 1)
4458 printf ("R%d END=0x%x\n", MONO_VARINFO (cfg, ins->inst_c0)->vreg, (int)(code - cfg->native_code));
4459 MONO_VARINFO (cfg, ins->inst_c0)->live_range_end = code - cfg->native_code;
4460 break;
4462 case OP_GC_SAFE_POINT:
4463 break;
4466 default:
4467 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4468 g_assert_not_reached ();
4471 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4472 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
4473 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
4474 g_assert_not_reached ();
4477 cpos += max_len;
4479 last_ins = ins;
4482 set_code_cursor (cfg, code);
4485 void
4486 mono_arch_register_lowlevel_calls (void)
4490 void
4491 mono_arch_patch_code (MonoCompile *cfg, MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors, MonoError *error)
4493 MonoJumpInfo *patch_info;
4495 error_init (error);
4497 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4498 unsigned char *ip = patch_info->ip.i + code;
4499 const unsigned char *target = NULL;
4501 switch (patch_info->type) {
4502 case MONO_PATCH_INFO_IP:
4503 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)ip);
4504 continue;
4505 case MONO_PATCH_INFO_SWITCH: {
4506 gpointer *table = (gpointer *)patch_info->data.table->table;
4507 int i;
4509 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)table);
4511 for (i = 0; i < patch_info->data.table->table_size; i++) {
4512 table [i] = (int)patch_info->data.table->table [i] + code;
4514 continue;
4516 case MONO_PATCH_INFO_METHODCONST:
4517 case MONO_PATCH_INFO_CLASS:
4518 case MONO_PATCH_INFO_IMAGE:
4519 case MONO_PATCH_INFO_FIELD:
4520 case MONO_PATCH_INFO_VTABLE:
4521 case MONO_PATCH_INFO_IID:
4522 case MONO_PATCH_INFO_SFLDA:
4523 case MONO_PATCH_INFO_LDSTR:
4524 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4525 case MONO_PATCH_INFO_LDTOKEN:
4526 case MONO_PATCH_INFO_R4:
4527 case MONO_PATCH_INFO_R8:
4528 /* from OP_AOTCONST : lui + addiu */
4529 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors, error);
4530 return_if_nok (error);
4532 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)target);
4533 continue;
4534 #if 0
4535 case MONO_PATCH_INFO_EXC_NAME:
4536 g_assert_not_reached ();
4537 *((gconstpointer *)(void *)(ip + 1)) = patch_info->data.name;
4538 continue;
4539 #endif
4540 case MONO_PATCH_INFO_NONE:
4541 /* everything is dealt with at epilog output time */
4542 continue;
4543 default:
4544 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors, error);
4545 return_if_nok (error);
4547 mips_patch ((guint32 *)(void *)ip, (guint32)target);
4548 break;
4553 void
4554 mips_adjust_stackframe(MonoCompile *cfg)
4556 MonoBasicBlock *bb;
4557 int delta, threshold, i;
4558 MonoMethodSignature *sig;
4559 int ra_offset;
4561 if (cfg->stack_offset == cfg->arch.local_alloc_offset)
4562 return;
4564 /* adjust cfg->stack_offset for account for down-spilling */
4565 cfg->stack_offset += SIZEOF_REGISTER;
4567 /* re-align cfg->stack_offset if needed (due to var spilling) */
4568 cfg->stack_offset = (cfg->stack_offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
4569 delta = cfg->stack_offset - cfg->arch.local_alloc_offset;
4570 if (cfg->verbose_level > 2) {
4571 g_print ("mips_adjust_stackframe:\n");
4572 g_print ("\tspillvars allocated 0x%x -> 0x%x\n", cfg->arch.local_alloc_offset, cfg->stack_offset);
4574 threshold = cfg->arch.local_alloc_offset;
4575 ra_offset = cfg->stack_offset - sizeof(gpointer);
4576 if (cfg->verbose_level > 2) {
4577 g_print ("\tra_offset %d/0x%x delta %d/0x%x\n", ra_offset, ra_offset, delta, delta);
4580 sig = mono_method_signature_internal (cfg->method);
4581 if (sig && sig->ret && MONO_TYPE_ISSTRUCT (sig->ret)) {
4582 cfg->vret_addr->inst_offset += delta;
4584 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4585 MonoInst *inst = cfg->args [i];
4587 inst->inst_offset += delta;
4591 * loads and stores based off the frame reg that (used to) lie
4592 * above the spill var area need to be increased by 'delta'
4593 * to make room for the spill vars.
4595 /* Need to find loads and stores to adjust that
4596 * are above where the spillvars were inserted, but
4597 * which are not the spillvar references themselves.
4599 * Idea - since all offsets from fp are positive, make
4600 * spillvar offsets negative to begin with so we can spot
4601 * them here.
4604 #if 1
4605 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4606 int ins_cnt = 0;
4607 MonoInst *ins;
4609 if (cfg->verbose_level > 2) {
4610 g_print ("BASIC BLOCK %d:\n", bb->block_num);
4612 MONO_BB_FOR_EACH_INS (bb, ins) {
4613 int adj_c0 = 0;
4614 int adj_imm = 0;
4616 if (cfg->verbose_level > 2) {
4617 mono_print_ins_index (ins_cnt, ins);
4619 /* The == mips_sp tests catch FP spills */
4620 if (MONO_IS_LOAD_MEMBASE(ins) && ((ins->inst_basereg == mips_fp) ||
4621 (ins->inst_basereg == mips_sp))) {
4622 switch (ins->opcode) {
4623 case OP_LOADI8_MEMBASE:
4624 case OP_LOADR8_MEMBASE:
4625 adj_c0 = 8;
4626 break;
4627 default:
4628 adj_c0 = 4;
4629 break;
4631 } else if (MONO_IS_STORE_MEMBASE(ins) && ((ins->dreg == mips_fp) ||
4632 (ins->dreg == mips_sp))) {
4633 switch (ins->opcode) {
4634 case OP_STOREI8_MEMBASE_REG:
4635 case OP_STORER8_MEMBASE_REG:
4636 case OP_STOREI8_MEMBASE_IMM:
4637 adj_c0 = 8;
4638 break;
4639 default:
4640 adj_c0 = 4;
4641 break;
4644 if (((ins->opcode == OP_ADD_IMM) || (ins->opcode == OP_IADD_IMM)) && (ins->sreg1 == cfg->frame_reg))
4645 adj_imm = 1;
4646 if (adj_c0) {
4647 if (ins->inst_c0 >= threshold) {
4648 ins->inst_c0 += delta;
4649 if (cfg->verbose_level > 2) {
4650 g_print ("adj");
4651 mono_print_ins_index (ins_cnt, ins);
4654 else if (ins->inst_c0 < 0) {
4655 /* Adj_c0 holds the size of the datatype. */
4656 ins->inst_c0 = - ins->inst_c0 - adj_c0;
4657 if (cfg->verbose_level > 2) {
4658 g_print ("spill");
4659 mono_print_ins_index (ins_cnt, ins);
4662 g_assert (ins->inst_c0 != ra_offset);
4664 if (adj_imm) {
4665 if (ins->inst_imm >= threshold) {
4666 ins->inst_imm += delta;
4667 if (cfg->verbose_level > 2) {
4668 g_print ("adj");
4669 mono_print_ins_index (ins_cnt, ins);
4672 g_assert (ins->inst_c0 != ra_offset);
4675 ++ins_cnt;
4678 #endif
4682 * Stack frame layout:
4684 * ------------------- sp + cfg->stack_usage + cfg->param_area
4685 * param area incoming
4686 * ------------------- sp + cfg->stack_usage + MIPS_STACK_PARAM_OFFSET
4687 * a0-a3 incoming
4688 * ------------------- sp + cfg->stack_usage
4689 * ra
4690 * ------------------- sp + cfg->stack_usage-4
4691 * spilled regs
4692 * ------------------- sp +
4693 * MonoLMF structure optional
4694 * ------------------- sp + cfg->arch.lmf_offset
4695 * saved registers s0-s8
4696 * ------------------- sp + cfg->arch.iregs_offset
4697 * locals
4698 * ------------------- sp + cfg->param_area
4699 * param area outgoing
4700 * ------------------- sp + MIPS_STACK_PARAM_OFFSET
4701 * a0-a3 outgoing
4702 * ------------------- sp
4703 * red zone
4705 guint8 *
4706 mono_arch_emit_prolog (MonoCompile *cfg)
4708 MonoMethod *method = cfg->method;
4709 MonoMethodSignature *sig;
4710 MonoInst *inst;
4711 int alloc_size, pos, i, max_offset;
4712 int alloc2_size = 0;
4713 guint8 *code;
4714 CallInfo *cinfo;
4715 guint32 iregs_to_save = 0;
4716 #if SAVE_FP_REGS
4717 guint32 fregs_to_save = 0;
4718 #endif
4719 /* lmf_offset is the offset of the LMF from our stack pointer. */
4720 guint32 lmf_offset = cfg->arch.lmf_offset;
4721 int cfa_offset = 0;
4722 MonoBasicBlock *bb;
4724 sig = mono_method_signature_internal (method);
4725 cfg->code_size = 768 + sig->param_count * 20;
4726 code = cfg->native_code = g_malloc (cfg->code_size);
4729 * compute max_offset in order to use short forward jumps.
4731 max_offset = 0;
4732 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4733 MonoInst *ins = bb->code;
4734 bb->max_offset = max_offset;
4736 MONO_BB_FOR_EACH_INS (bb, ins)
4737 max_offset += ins_get_size (ins->opcode);
4739 if (max_offset > 0xffff)
4740 cfg->arch.long_branch = TRUE;
4743 * Currently, fp points to the bottom of the frame on MIPS, unlike other platforms.
4744 * This means that we have to adjust the offsets inside instructions which reference
4745 * arguments received on the stack, since the initial offset doesn't take into
4746 * account spill slots.
4748 mips_adjust_stackframe (cfg);
4750 /* Offset between current sp and the CFA */
4751 cfa_offset = 0;
4752 mono_emit_unwind_op_def_cfa (cfg, code, mips_sp, cfa_offset);
4754 /* stack_offset should not be changed here. */
4755 alloc_size = cfg->stack_offset;
4756 cfg->stack_usage = alloc_size;
4758 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
4759 #if SAVE_FP_REGS
4760 #if 0
4761 fregs_to_save = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
4762 #else
4763 fregs_to_save = MONO_ARCH_CALLEE_SAVED_FREGS;
4764 fregs_to_save |= (fregs_to_save << 1);
4765 #endif
4766 #endif
4767 /* If the stack size is too big, save 1024 bytes to start with
4768 * so the prologue can use imm16(reg) addressing, then allocate
4769 * the rest of the frame.
4771 if (alloc_size > ((1 << 15) - 1024)) {
4772 alloc2_size = alloc_size - 1024;
4773 alloc_size = 1024;
4775 if (alloc_size) {
4776 g_assert (mips_is_imm16 (-alloc_size));
4777 mips_addiu (code, mips_sp, mips_sp, -alloc_size);
4778 cfa_offset = alloc_size;
4779 mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
4782 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
4783 int offset = alloc_size + MIPS_RET_ADDR_OFFSET;
4784 if (mips_is_imm16(offset))
4785 mips_sw (code, mips_ra, mips_sp, offset);
4786 else {
4787 g_assert_not_reached ();
4789 /* sp = cfa - cfa_offset, so sp + offset = cfa - cfa_offset + offset */
4790 mono_emit_unwind_op_offset (cfg, code, mips_ra, offset - cfa_offset);
4793 /* XXX - optimize this later to not save all regs if LMF constructed */
4794 pos = cfg->arch.iregs_offset - alloc2_size;
4796 if (iregs_to_save) {
4797 /* save used registers in own stack frame (at pos) */
4798 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
4799 if (iregs_to_save & (1 << i)) {
4800 g_assert (pos < (int)(cfg->stack_usage - sizeof(gpointer)));
4801 g_assert (mips_is_imm16(pos));
4802 MIPS_SW (code, i, mips_sp, pos);
4803 mono_emit_unwind_op_offset (cfg, code, i, pos - cfa_offset);
4804 pos += SIZEOF_REGISTER;
4809 // FIXME: Don't save registers twice if there is an LMF
4810 // s8 has to be special cased since it is overwritten with the updated value
4811 // below
4812 if (method->save_lmf) {
4813 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
4814 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[i]);
4815 g_assert (mips_is_imm16(offset));
4816 if (MIPS_LMF_IREGMASK & (1 << i))
4817 MIPS_SW (code, i, mips_sp, offset);
4821 #if SAVE_FP_REGS
4822 /* Save float registers */
4823 if (fregs_to_save) {
4824 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
4825 if (fregs_to_save & (1 << i)) {
4826 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
4827 g_assert (mips_is_imm16(pos));
4828 mips_swc1 (code, i, mips_sp, pos);
4829 pos += sizeof (gulong);
4834 if (method->save_lmf) {
4835 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
4836 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, fregs[i]);
4837 g_assert (mips_is_imm16(offset));
4838 mips_swc1 (code, i, mips_sp, offset);
4842 #endif
4843 if (cfg->frame_reg != mips_sp) {
4844 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
4845 mono_emit_unwind_op_def_cfa (cfg, code, cfg->frame_reg, cfa_offset);
4847 if (method->save_lmf) {
4848 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[cfg->frame_reg]);
4849 g_assert (mips_is_imm16(offset));
4850 MIPS_SW (code, cfg->frame_reg, mips_sp, offset);
4854 /* store runtime generic context */
4855 if (cfg->rgctx_var) {
4856 MonoInst *ins = cfg->rgctx_var;
4858 g_assert (ins->opcode == OP_REGOFFSET);
4860 g_assert (mips_is_imm16 (ins->inst_offset));
4861 mips_sw (code, MONO_ARCH_RGCTX_REG, ins->inst_basereg, ins->inst_offset);
4864 /* load arguments allocated to register from the stack */
4865 pos = 0;
4867 if (!cfg->arch.cinfo)
4868 cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
4869 cinfo = cfg->arch.cinfo;
4871 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
4872 ArgInfo *ainfo = &cinfo->ret;
4873 inst = cfg->vret_addr;
4874 if (inst->opcode == OP_REGVAR)
4875 MIPS_MOVE (code, inst->dreg, ainfo->reg);
4876 else if (mips_is_imm16 (inst->inst_offset)) {
4877 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4878 } else {
4879 mips_load_const (code, mips_at, inst->inst_offset);
4880 mips_addu (code, mips_at, mips_at, inst->inst_basereg);
4881 mips_sw (code, ainfo->reg, mips_at, 0);
4885 if (sig->call_convention == MONO_CALL_VARARG) {
4886 ArgInfo *cookie = &cinfo->sig_cookie;
4887 int offset = alloc_size + cookie->offset;
4889 /* Save the sig cookie address */
4890 g_assert (cookie->storage == ArgOnStack);
4892 g_assert (mips_is_imm16(offset));
4893 mips_addi (code, mips_at, cfg->frame_reg, offset);
4894 mips_sw (code, mips_at, cfg->frame_reg, cfg->sig_cookie - alloc2_size);
4897 /* Keep this in sync with emit_load_volatile_arguments */
4898 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4899 ArgInfo *ainfo = cinfo->args + i;
4900 inst = cfg->args [pos];
4902 if (cfg->verbose_level > 2)
4903 g_print ("Saving argument %d (type: %d)\n", i, ainfo->storage);
4904 if (inst->opcode == OP_REGVAR) {
4905 /* Argument ends up in a register */
4906 if (ainfo->storage == ArgInIReg)
4907 MIPS_MOVE (code, inst->dreg, ainfo->reg);
4908 else if (ainfo->storage == ArgInFReg) {
4909 g_assert_not_reached();
4910 #if 0
4911 ppc_fmr (code, inst->dreg, ainfo->reg);
4912 #endif
4914 else if (ainfo->storage == ArgOnStack) {
4915 int offset = cfg->stack_usage + ainfo->offset;
4916 g_assert (mips_is_imm16(offset));
4917 mips_lw (code, inst->dreg, mips_sp, offset);
4918 } else
4919 g_assert_not_reached ();
4921 if (cfg->verbose_level > 2)
4922 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
4923 } else {
4924 /* Argument ends up on the stack */
4925 if (ainfo->storage == ArgInIReg) {
4926 int basereg_offset;
4927 /* Incoming parameters should be above this frame */
4928 if (cfg->verbose_level > 2)
4929 g_print ("stack slot at %d of %d+%d\n",
4930 inst->inst_offset, alloc_size, alloc2_size);
4931 /* g_assert (inst->inst_offset >= alloc_size); */
4932 g_assert (inst->inst_basereg == cfg->frame_reg);
4933 basereg_offset = inst->inst_offset - alloc2_size;
4934 g_assert (mips_is_imm16 (basereg_offset));
4935 switch (ainfo->size) {
4936 case 1:
4937 mips_sb (code, ainfo->reg, inst->inst_basereg, basereg_offset);
4938 break;
4939 case 2:
4940 mips_sh (code, ainfo->reg, inst->inst_basereg, basereg_offset);
4941 break;
4942 case 0: /* XXX */
4943 case 4:
4944 mips_sw (code, ainfo->reg, inst->inst_basereg, basereg_offset);
4945 break;
4946 case 8:
4947 #if (SIZEOF_REGISTER == 4)
4948 mips_sw (code, ainfo->reg, inst->inst_basereg, basereg_offset + ls_word_offset);
4949 mips_sw (code, ainfo->reg + 1, inst->inst_basereg, basereg_offset + ms_word_offset);
4950 #elif (SIZEOF_REGISTER == 8)
4951 mips_sd (code, ainfo->reg, inst->inst_basereg, basereg_offset);
4952 #endif
4953 break;
4954 default:
4955 g_assert_not_reached ();
4956 break;
4958 } else if (ainfo->storage == ArgOnStack) {
4960 * Argument comes in on the stack, and ends up on the stack
4961 * 1 and 2 byte args are passed as 32-bit quantities, but used as
4962 * 8 and 16 bit quantities. Shorten them in place.
4964 g_assert (mips_is_imm16 (inst->inst_offset));
4965 switch (ainfo->size) {
4966 case 1:
4967 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
4968 mips_sb (code, mips_at, inst->inst_basereg, inst->inst_offset);
4969 break;
4970 case 2:
4971 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
4972 mips_sh (code, mips_at, inst->inst_basereg, inst->inst_offset);
4973 break;
4974 case 0: /* XXX */
4975 case 4:
4976 case 8:
4977 break;
4978 default:
4979 g_assert_not_reached ();
4981 } else if (ainfo->storage == ArgInFReg) {
4982 g_assert (mips_is_imm16 (inst->inst_offset));
4983 g_assert (mips_is_imm16 (inst->inst_offset+4));
4984 if (ainfo->size == 8) {
4985 #if _MIPS_SIM == _ABIO32
4986 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
4987 mips_swc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
4988 #elif _MIPS_SIM == _ABIN32
4989 mips_sdc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4990 #endif
4992 else if (ainfo->size == 4)
4993 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4994 else
4995 g_assert_not_reached ();
4996 } else if (ainfo->storage == ArgStructByVal) {
4997 int i;
4998 int doffset = inst->inst_offset;
5000 g_assert (mips_is_imm16 (inst->inst_offset));
5001 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (target_mgreg_t)));
5002 /* Push the argument registers into their stack slots */
5003 for (i = 0; i < ainfo->size; ++i) {
5004 g_assert (mips_is_imm16(doffset));
5005 MIPS_SW (code, ainfo->reg + i, inst->inst_basereg, doffset);
5006 doffset += SIZEOF_REGISTER;
5008 } else if (ainfo->storage == ArgStructByAddr) {
5009 g_assert (mips_is_imm16 (inst->inst_offset));
5010 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
5011 code = emit_memcpy (code, ainfo->vtsize * sizeof (target_mgreg_t), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
5012 } else
5013 g_assert_not_reached ();
5015 pos++;
5018 if (method->save_lmf) {
5019 mips_load_const (code, mips_at, MIPS_LMF_MAGIC1);
5020 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, magic));
5022 /* This can/will clobber the a0-a3 registers */
5023 mips_call (code, mips_t9, (gpointer)mono_get_lmf_addr);
5025 /* mips_v0 is the result from mono_get_lmf_addr () (MonoLMF **) */
5026 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5027 mips_sw (code, mips_v0, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5028 /* new_lmf->previous_lmf = *lmf_addr */
5029 mips_lw (code, mips_at, mips_v0, 0);
5030 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5031 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5032 /* *(lmf_addr) = sp + lmf_offset */
5033 g_assert (mips_is_imm16(lmf_offset));
5034 mips_addiu (code, mips_at, mips_sp, lmf_offset);
5035 mips_sw (code, mips_at, mips_v0, 0);
5037 /* save method info */
5038 mips_load_const (code, mips_at, method);
5039 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, method)));
5040 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, method));
5042 /* save the current IP */
5043 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5044 mips_load_const (code, mips_at, 0x01010101);
5045 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, eip));
5048 if (alloc2_size) {
5049 if (mips_is_imm16 (-alloc2_size)) {
5050 mips_addu (code, mips_sp, mips_sp, -alloc2_size);
5052 else {
5053 mips_load_const (code, mips_at, -alloc2_size);
5054 mips_addu (code, mips_sp, mips_sp, mips_at);
5056 alloc_size += alloc2_size;
5057 cfa_offset += alloc2_size;
5058 if (cfg->frame_reg != mips_sp)
5059 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
5060 else
5061 mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
5064 set_code_cursor (cfg, code);
5066 return code;
5069 guint8 *
5070 mono_arch_emit_epilog_sub (MonoCompile *cfg)
5072 guint8 *code = NULL;
5073 MonoMethod *method = cfg->method;
5074 int i;
5075 int max_epilog_size = 16 + 20*4;
5076 int alloc2_size = 0;
5077 guint32 iregs_to_restore;
5078 #if SAVE_FP_REGS
5079 guint32 fregs_to_restore;
5080 #endif
5082 if (cfg->method->save_lmf)
5083 max_epilog_size += 128;
5085 realloc_code (cfg, max_epilog_size);
5087 code = cfg->native_code + cfg->code_len;
5089 if (cfg->frame_reg != mips_sp) {
5090 MIPS_MOVE (code, mips_sp, cfg->frame_reg);
5092 /* If the stack frame is really large, deconstruct it in two steps */
5093 if (cfg->stack_usage > ((1 << 15) - 1024)) {
5094 alloc2_size = cfg->stack_usage - 1024;
5095 /* partially deconstruct the stack */
5096 mips_load_const (code, mips_at, alloc2_size);
5097 mips_addu (code, mips_sp, mips_sp, mips_at);
5099 int pos = cfg->arch.iregs_offset - alloc2_size;
5100 iregs_to_restore = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
5101 if (iregs_to_restore) {
5102 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5103 if (iregs_to_restore & (1 << i)) {
5104 g_assert (mips_is_imm16(pos));
5105 MIPS_LW (code, i, mips_sp, pos);
5106 pos += SIZEOF_REGISTER;
5111 #if SAVE_FP_REGS
5112 #if 0
5113 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
5114 #else
5115 fregs_to_restore = MONO_ARCH_CALLEE_SAVED_FREGS;
5116 fregs_to_restore |= (fregs_to_restore << 1);
5117 #endif
5118 if (fregs_to_restore) {
5119 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5120 if (fregs_to_restore & (1 << i)) {
5121 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
5122 g_assert (mips_is_imm16(pos));
5123 mips_lwc1 (code, i, mips_sp, pos);
5124 pos += FREG_SIZE
5128 #endif
5130 /* Unlink the LMF if necessary */
5131 if (method->save_lmf) {
5132 int lmf_offset = cfg->arch.lmf_offset;
5134 /* t0 = current_lmf->previous_lmf */
5135 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5136 mips_lw (code, mips_temp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5137 /* t1 = lmf_addr */
5138 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5139 mips_lw (code, mips_t1, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5140 /* (*lmf_addr) = previous_lmf */
5141 mips_sw (code, mips_temp, mips_t1, 0);
5144 #if 0
5145 /* Restore the fp */
5146 mips_lw (code, mips_fp, mips_sp, cfg->stack_usage + MIPS_FP_ADDR_OFFSET);
5147 #endif
5148 /* Restore ra */
5149 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
5150 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET));
5151 mips_lw (code, mips_ra, mips_sp, cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET);
5153 /* Restore the stack pointer */
5154 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size));
5155 mips_addiu (code, mips_sp, mips_sp, cfg->stack_usage - alloc2_size);
5157 /* Caller will emit either return or tail-call sequence */
5159 set_code_cursor (cfg, code);
5161 return (code);
5164 void
5165 mono_arch_emit_epilog (MonoCompile *cfg)
5167 guint8 *code = mono_arch_emit_epilog_sub (cfg);
5169 mips_jr (code, mips_ra);
5170 mips_nop (code);
5172 set_code_cursor (cfg, code);
5175 /* remove once throw_exception_by_name is eliminated */
5176 #if 0
5177 static int
5178 exception_id_by_name (const char *name)
5180 if (strcmp (name, "IndexOutOfRangeException") == 0)
5181 return MONO_EXC_INDEX_OUT_OF_RANGE;
5182 if (strcmp (name, "OverflowException") == 0)
5183 return MONO_EXC_OVERFLOW;
5184 if (strcmp (name, "ArithmeticException") == 0)
5185 return MONO_EXC_ARITHMETIC;
5186 if (strcmp (name, "DivideByZeroException") == 0)
5187 return MONO_EXC_DIVIDE_BY_ZERO;
5188 if (strcmp (name, "InvalidCastException") == 0)
5189 return MONO_EXC_INVALID_CAST;
5190 if (strcmp (name, "NullReferenceException") == 0)
5191 return MONO_EXC_NULL_REF;
5192 if (strcmp (name, "ArrayTypeMismatchException") == 0)
5193 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5194 if (strcmp (name, "ArgumentException") == 0)
5195 return MONO_EXC_ARGUMENT;
5196 g_error ("Unknown intrinsic exception %s\n", name);
5197 return 0;
5199 #endif
5201 void
5202 mono_arch_emit_exceptions (MonoCompile *cfg)
5204 #if 0
5205 MonoJumpInfo *patch_info;
5206 int i;
5207 guint8 *code;
5208 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
5209 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
5210 int max_epilog_size = 50;
5212 /* count the number of exception infos */
5215 * make sure we have enough space for exceptions
5216 * 24 is the simulated call to throw_exception_by_name
5218 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5219 #if 0
5220 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5221 i = exception_id_by_name (patch_info->data.target);
5222 g_assert (i < MONO_EXC_INTRINS_NUM);
5223 if (!exc_throw_found [i]) {
5224 max_epilog_size += 12;
5225 exc_throw_found [i] = TRUE;
5228 #endif
5231 code = realloc_code (cfg, max_epilog_size);
5233 /* add code to raise exceptions */
5234 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5235 switch (patch_info->type) {
5236 case MONO_PATCH_INFO_EXC: {
5237 g_assert_not_reached();
5238 break;
5240 default:
5241 /* do nothing */
5242 break;
5246 set_code_cursor (cfg, code);
5247 #endif
5250 void
5251 mono_arch_finish_init (void)
5255 void
5256 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
5258 int this_dreg = mips_a0;
5260 if (vt_reg != -1)
5261 this_dreg = mips_a1;
5263 /* add the this argument */
5264 if (this_reg != -1) {
5265 MonoInst *this_ins;
5266 MONO_INST_NEW (cfg, this_ins, OP_MOVE);
5267 this_ins->type = this_type;
5268 this_ins->sreg1 = this_reg;
5269 this_ins->dreg = mono_alloc_ireg (cfg);
5270 mono_bblock_add_inst (cfg->cbb, this_ins);
5271 mono_call_inst_add_outarg_reg (cfg, inst, this_ins->dreg, this_dreg, FALSE);
5274 if (vt_reg != -1) {
5275 MonoInst *vtarg;
5276 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
5277 vtarg->type = STACK_MP;
5278 vtarg->sreg1 = vt_reg;
5279 vtarg->dreg = mono_alloc_ireg (cfg);
5280 mono_bblock_add_inst (cfg->cbb, vtarg);
5281 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, mips_a0, FALSE);
5285 MonoInst*
5286 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5288 MonoInst *ins = NULL;
5290 return ins;
5293 MonoInst*
5294 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5296 return NULL;
5299 host_mgreg_t
5300 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5302 return ctx->sc_regs [reg];
5305 #define ENABLE_WRONG_METHOD_CHECK 0
5307 #define MIPS_LOAD_SEQUENCE_LENGTH 8
5308 #define CMP_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 4)
5309 #define BR_SIZE 8
5310 #define LOADSTORE_SIZE 4
5311 #define JUMP_IMM_SIZE 16
5312 #define JUMP_IMM32_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 8)
5313 #define LOAD_CONST_SIZE 8
5314 #define JUMP_JR_SIZE 8
5317 * LOCKING: called with the domain lock held
5319 gpointer
5320 mono_arch_build_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5321 gpointer fail_tramp)
5323 int i;
5324 int size = 0;
5325 guint8 *code, *start, *patch;
5327 for (i = 0; i < count; ++i) {
5328 MonoIMTCheckItem *item = imt_entries [i];
5330 if (item->is_equals) {
5331 if (item->check_target_idx) {
5332 item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_JR_SIZE;
5333 if (item->has_target_code)
5334 item->chunk_size += LOAD_CONST_SIZE;
5335 else
5336 item->chunk_size += LOADSTORE_SIZE;
5337 } else {
5338 if (fail_tramp) {
5339 item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_IMM32_SIZE +
5340 LOADSTORE_SIZE + JUMP_IMM32_SIZE;
5341 if (!item->has_target_code)
5342 item->chunk_size += LOADSTORE_SIZE;
5343 } else {
5344 item->chunk_size += LOADSTORE_SIZE + JUMP_JR_SIZE;
5345 #if ENABLE_WRONG_METHOD_CHECK
5346 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5347 #endif
5350 } else {
5351 item->chunk_size += CMP_SIZE + BR_SIZE;
5352 imt_entries [item->check_target_idx]->compare_done = TRUE;
5354 size += item->chunk_size;
5356 /* the initial load of the vtable address */
5357 size += MIPS_LOAD_SEQUENCE_LENGTH;
5358 if (fail_tramp) {
5359 code = mono_method_alloc_generic_virtual_trampoline (domain, size);
5360 } else {
5361 code = mono_domain_code_reserve (domain, size);
5363 start = code;
5365 /* t7 points to the vtable */
5366 mips_load_const (code, mips_t7, (gsize)(& (vtable->vtable [0])));
5368 for (i = 0; i < count; ++i) {
5369 MonoIMTCheckItem *item = imt_entries [i];
5371 item->code_target = code;
5372 if (item->is_equals) {
5373 if (item->check_target_idx) {
5374 mips_load_const (code, mips_temp, (gsize)item->key);
5375 item->jmp_code = code;
5376 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5377 mips_nop (code);
5378 if (item->has_target_code) {
5379 mips_load_const (code, mips_t9,
5380 item->value.target_code);
5382 else {
5383 mips_lw (code, mips_t9, mips_t7,
5384 (sizeof (target_mgreg_t) * item->value.vtable_slot));
5386 mips_jr (code, mips_t9);
5387 mips_nop (code);
5388 } else {
5389 if (fail_tramp) {
5390 mips_load_const (code, mips_temp, (gsize)item->key);
5391 patch = code;
5392 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5393 mips_nop (code);
5394 if (item->has_target_code) {
5395 mips_load_const (code, mips_t9,
5396 item->value.target_code);
5397 } else {
5398 g_assert (vtable);
5399 mips_load_const (code, mips_at,
5400 & (vtable->vtable [item->value.vtable_slot]));
5401 mips_lw (code, mips_t9, mips_at, 0);
5403 mips_jr (code, mips_t9);
5404 mips_nop (code);
5405 mips_patch ((guint32 *)(void *)patch, (guint32)code);
5406 mips_load_const (code, mips_t9, fail_tramp);
5407 mips_jr (code, mips_t9);
5408 mips_nop (code);
5409 } else {
5410 /* enable the commented code to assert on wrong method */
5411 #if ENABLE_WRONG_METHOD_CHECK
5412 ppc_load (code, ppc_r0, (guint32)item->key);
5413 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5414 patch = code;
5415 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5416 #endif
5417 mips_lw (code, mips_t9, mips_t7,
5418 (sizeof (target_mgreg_t) * item->value.vtable_slot));
5419 mips_jr (code, mips_t9);
5420 mips_nop (code);
5422 #if ENABLE_WRONG_METHOD_CHECK
5423 ppc_patch (patch, code);
5424 ppc_break (code);
5425 #endif
5428 } else {
5429 mips_load_const (code, mips_temp, (gulong)item->key);
5430 mips_slt (code, mips_temp, MONO_ARCH_IMT_REG, mips_temp);
5432 item->jmp_code = code;
5433 mips_beq (code, mips_temp, mips_zero, 0);
5434 mips_nop (code);
5437 /* patch the branches to get to the target items */
5438 for (i = 0; i < count; ++i) {
5439 MonoIMTCheckItem *item = imt_entries [i];
5440 if (item->jmp_code && item->check_target_idx) {
5441 mips_patch ((guint32 *)item->jmp_code,
5442 (guint32)imt_entries [item->check_target_idx]->code_target);
5446 if (!fail_tramp)
5447 UnlockedAdd (&mono_stats.imt_trampolines_size, code - start);
5448 g_assert (code - start <= size);
5449 mono_arch_flush_icache (start, size);
5450 MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_IMT_TRAMPOLINE, NULL));
5452 mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), domain);
5454 return start;
5457 MonoMethod*
5458 mono_arch_find_imt_method (host_mgreg_t *regs, guint8 *code)
5460 return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
5463 MonoVTable*
5464 mono_arch_find_static_call_vtable (host_mgreg_t *regs, guint8 *code)
5466 return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
5469 /* Soft Debug support */
5470 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
5473 * mono_arch_set_breakpoint:
5475 * See mini-amd64.c for docs.
5477 void
5478 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
5480 guint8 *code = ip;
5481 guint32 addr = (guint32)bp_trigger_page;
5483 mips_load_const (code, mips_t9, addr);
5484 mips_lw (code, mips_t9, mips_t9, 0);
5486 mono_arch_flush_icache (ip, code - ip);
5490 * mono_arch_clear_breakpoint:
5492 * See mini-amd64.c for docs.
5494 void
5495 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
5497 guint8 *code = ip;
5499 mips_nop (code);
5500 mips_nop (code);
5501 mips_nop (code);
5503 mono_arch_flush_icache (ip, code - ip);
5507 * mono_arch_start_single_stepping:
5509 * See mini-amd64.c for docs.
5511 void
5512 mono_arch_start_single_stepping (void)
5514 mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
5518 * mono_arch_stop_single_stepping:
5520 * See mini-amd64.c for docs.
5522 void
5523 mono_arch_stop_single_stepping (void)
5525 mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
5529 * mono_arch_is_single_step_event:
5531 * See mini-amd64.c for docs.
5533 gboolean
5534 mono_arch_is_single_step_event (void *info, void *sigctx)
5536 siginfo_t* sinfo = (siginfo_t*) info;
5537 /* Sometimes the address is off by 4 */
5538 if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
5539 return TRUE;
5540 else
5541 return FALSE;
5545 * mono_arch_is_breakpoint_event:
5547 * See mini-amd64.c for docs.
5549 gboolean
5550 mono_arch_is_breakpoint_event (void *info, void *sigctx)
5552 siginfo_t* sinfo = (siginfo_t*) info;
5553 /* Sometimes the address is off by 4 */
5554 if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
5555 return TRUE;
5556 else
5557 return FALSE;
5561 * mono_arch_skip_breakpoint:
5563 * See mini-amd64.c for docs.
5565 void
5566 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
5568 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
5572 * mono_arch_skip_single_step:
5574 * See mini-amd64.c for docs.
5576 void
5577 mono_arch_skip_single_step (MonoContext *ctx)
5579 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
5583 * mono_arch_get_seq_point_info:
5585 * See mini-amd64.c for docs.
5587 SeqPointInfo*
5588 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
5590 NOT_IMPLEMENTED;
5591 return NULL;
5594 #endif /* MONO_ARCH_SOFT_DEBUG_SUPPORTED */
5596 gboolean
5597 mono_arch_opcode_supported (int opcode)
5599 return FALSE;
5602 gboolean
5603 mono_arch_tailcall_supported (MonoCompile *cfg, MonoMethodSignature *caller_sig, MonoMethodSignature *callee_sig, gboolean virtual_)
5605 return FALSE;
5608 gpointer
5609 mono_arch_load_function (MonoJitICallId jit_icall_id)
5611 return NULL;