[netcore] Implement missing Bmi1/Bmi2 intrinsics (#16919)
[mono-project.git] / mono / mini / mini-mips.c
bloba34895055283bcb5068bd0cc9b55d370cb20921d
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"
34 #define SAVE_FP_REGS 0
36 #define ALWAYS_SAVE_RA 1 /* call-handler & switch currently clobber ra */
38 #define PROMOTE_R4_TO_R8 1 /* promote single values in registers to doubles */
39 #define USE_MUL 0 /* use mul instead of mult/mflo for multiply
40 remember to update cpu-mips.md if you change this */
42 /* Emit a call sequence to 'v', using 'D' as a scratch register if necessary */
43 #define mips_call(c,D,v) do { \
44 guint32 _target = (guint32)(v); \
45 if (1 || ((v) == NULL) || ((_target & 0xfc000000) != (((guint32)(c)) & 0xfc000000))) { \
46 mips_load_const (c, D, _target); \
47 mips_jalr (c, D, mips_ra); \
48 } \
49 else { \
50 mips_jumpl (c, _target >> 2); \
51 } \
52 mips_nop (c); \
53 } while (0)
55 enum {
56 TLS_MODE_DETECT,
57 TLS_MODE_FAILED,
58 TLS_MODE_LTHREADS,
59 TLS_MODE_NPTL
62 /* This mutex protects architecture specific caches */
63 #define mono_mini_arch_lock() mono_os_mutex_lock (&mini_arch_mutex)
64 #define mono_mini_arch_unlock() mono_os_mutex_unlock (&mini_arch_mutex)
65 static mono_mutex_t mini_arch_mutex;
67 /* Whenever the host is little-endian */
68 static int little_endian;
69 /* Index of ms word/register */
70 static int ls_word_idx;
71 /* Index of ls word/register */
72 static int ms_word_idx;
73 /* Same for offsets */
74 static int ls_word_offset;
75 static int ms_word_offset;
78 * The code generated for sequence points reads from this location, which is
79 * made read-only when single stepping is enabled.
81 static gpointer ss_trigger_page;
83 /* Enabled breakpoints read from this trigger page */
84 static gpointer bp_trigger_page;
86 #undef DEBUG
87 #define DEBUG(a) if (cfg->verbose_level > 1) a
88 #undef DEBUG
89 #define DEBUG(a) a
90 #undef DEBUG
91 #define DEBUG(a)
93 #define EMIT_SYSTEM_EXCEPTION_NAME(exc_name) \
94 do { \
95 code = mips_emit_exc_by_name (code, exc_name); \
96 cfg->bb_exit->max_offset += 16; \
97 } while (0)
99 #define MONO_EMIT_NEW_LOAD_R8(cfg,dr,addr) do { \
100 MonoInst *inst; \
101 MONO_INST_NEW ((cfg), (inst), OP_R8CONST); \
102 inst->type = STACK_R8; \
103 inst->dreg = (dr); \
104 inst->inst_p0 = (void*)(addr); \
105 mono_bblock_add_inst (cfg->cbb, inst); \
106 } while (0)
108 #define ins_is_compare(ins) ((ins) && (((ins)->opcode == OP_COMPARE) \
109 || ((ins)->opcode == OP_ICOMPARE) \
110 || ((ins)->opcode == OP_LCOMPARE)))
111 #define ins_is_compare_imm(ins) ((ins) && (((ins)->opcode == OP_COMPARE_IMM) \
112 || ((ins)->opcode == OP_ICOMPARE_IMM) \
113 || ((ins)->opcode == OP_LCOMPARE_IMM)))
115 #define INS_REWRITE(ins, op, _s1, _s2) do { \
116 int s1 = _s1; \
117 int s2 = _s2; \
118 ins->opcode = (op); \
119 ins->sreg1 = (s1); \
120 ins->sreg2 = (s2); \
121 } while (0);
123 #define INS_REWRITE_IMM(ins, op, _s1, _imm) do { \
124 int s1 = _s1; \
125 ins->opcode = (op); \
126 ins->sreg1 = (s1); \
127 ins->inst_imm = (_imm); \
128 } while (0);
131 typedef struct InstList InstList;
133 struct InstList {
134 InstList *prev;
135 InstList *next;
136 MonoInst *data;
139 typedef enum {
140 ArgInIReg,
141 ArgOnStack,
142 ArgInFReg,
143 ArgStructByVal,
144 ArgStructByAddr
145 } ArgStorage;
147 typedef struct {
148 gint32 offset;
149 guint16 vtsize; /* in param area */
150 guint8 reg;
151 ArgStorage storage;
152 guint8 size : 4; /* 1, 2, 4, 8, or regs used by ArgStructByVal */
153 } ArgInfo;
155 struct CallInfo {
156 int nargs;
157 int gr;
158 int fr;
159 gboolean gr_passed;
160 gboolean on_stack;
161 gboolean vtype_retaddr;
162 int stack_size;
163 guint32 stack_usage;
164 guint32 struct_ret;
165 ArgInfo ret;
166 ArgInfo sig_cookie;
167 ArgInfo args [1];
170 void patch_lui_addiu(guint32 *ip, guint32 val);
171 static
172 guint8 *mono_arch_emit_epilog_sub (MonoCompile *cfg);
173 guint8 *mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins);
174 void mips_adjust_stackframe(MonoCompile *cfg);
175 void mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg);
176 MonoInst *mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args);
179 /* Not defined in asm/cachectl.h */
180 int cacheflush(char *addr, int nbytes, int cache);
182 void
183 mono_arch_flush_icache (guint8 *code, gint size)
185 /* Linux/MIPS specific */
186 cacheflush ((char*)code, size, BCACHE);
189 void
190 mono_arch_flush_register_windows (void)
194 gboolean
195 mono_arch_is_inst_imm (int opcode, int imm_opcode, gint64 imm)
197 return TRUE;
200 static guint8 *
201 mips_emit_exc_by_name(guint8 *code, const char *name)
203 gpointer addr;
204 MonoClass *exc_class;
206 exc_class = mono_class_load_from_name (mono_defaults.corlib, "System", name);
208 mips_load_const (code, mips_a0, m_class_get_type_token (exc_class));
209 addr = mono_get_throw_corlib_exception ();
210 mips_call (code, mips_t9, addr);
211 return code;
214 guint8 *
215 mips_emit_load_const (guint8 *code, int dreg, target_mgreg_t v)
217 if (mips_is_imm16 (v))
218 mips_addiu (code, dreg, mips_zero, ((guint32)v) & 0xffff);
219 else {
220 #if SIZEOF_REGISTER == 8
221 if (v != (long) v) {
222 /* v is not a sign-extended 32-bit value */
223 mips_lui (code, dreg, mips_zero, (guint32)((v >> (32+16)) & 0xffff));
224 mips_ori (code, dreg, dreg, (guint32)((v >> (32)) & 0xffff));
225 mips_dsll (code, dreg, dreg, 16);
226 mips_ori (code, dreg, dreg, (guint32)((v >> (16)) & 0xffff));
227 mips_dsll (code, dreg, dreg, 16);
228 mips_ori (code, dreg, dreg, (guint32)(v & 0xffff));
229 return code;
231 #endif
232 if (((guint32)v) & (1 << 15)) {
233 mips_lui (code, dreg, mips_zero, (((guint32)v)>>16)+1);
235 else {
236 mips_lui (code, dreg, mips_zero, (((guint32)v)>>16));
238 if (((guint32)v) & 0xffff)
239 mips_addiu (code, dreg, dreg, ((guint32)v) & 0xffff);
241 return code;
244 guint8 *
245 mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins)
247 g_assert (ins);
248 if (cfg->arch.long_branch) {
249 int br_offset = 5;
251 /* Invert test and emit branch around jump */
252 switch (op) {
253 case OP_MIPS_BEQ:
254 mips_bne (code, ins->sreg1, ins->sreg2, br_offset);
255 mips_nop (code);
256 break;
257 case OP_MIPS_BNE:
258 mips_beq (code, ins->sreg1, ins->sreg2, br_offset);
259 mips_nop (code);
260 break;
261 case OP_MIPS_BGEZ:
262 mips_bltz (code, ins->sreg1, br_offset);
263 mips_nop (code);
264 break;
265 case OP_MIPS_BGTZ:
266 mips_blez (code, ins->sreg1, br_offset);
267 mips_nop (code);
268 break;
269 case OP_MIPS_BLEZ:
270 mips_bgtz (code, ins->sreg1, br_offset);
271 mips_nop (code);
272 break;
273 case OP_MIPS_BLTZ:
274 mips_bgez (code, ins->sreg1, br_offset);
275 mips_nop (code);
276 break;
277 default:
278 g_assert_not_reached ();
280 mono_add_patch_info (cfg, code - cfg->native_code,
281 MONO_PATCH_INFO_BB, ins->inst_true_bb);
282 mips_lui (code, mips_at, mips_zero, 0);
283 mips_addiu (code, mips_at, mips_at, 0);
284 mips_jr (code, mips_at);
285 mips_nop (code);
287 else {
288 mono_add_patch_info (cfg, code - cfg->native_code,
289 MONO_PATCH_INFO_BB, ins->inst_true_bb);
290 switch (op) {
291 case OP_MIPS_BEQ:
292 mips_beq (code, ins->sreg1, ins->sreg2, 0);
293 mips_nop (code);
294 break;
295 case OP_MIPS_BNE:
296 mips_bne (code, ins->sreg1, ins->sreg2, 0);
297 mips_nop (code);
298 break;
299 case OP_MIPS_BGEZ:
300 mips_bgez (code, ins->sreg1, 0);
301 mips_nop (code);
302 break;
303 case OP_MIPS_BGTZ:
304 mips_bgtz (code, ins->sreg1, 0);
305 mips_nop (code);
306 break;
307 case OP_MIPS_BLEZ:
308 mips_blez (code, ins->sreg1, 0);
309 mips_nop (code);
310 break;
311 case OP_MIPS_BLTZ:
312 mips_bltz (code, ins->sreg1, 0);
313 mips_nop (code);
314 break;
315 default:
316 g_assert_not_reached ();
319 return (code);
322 /* XXX - big-endian dependent? */
323 void
324 patch_lui_addiu(guint32 *ip, guint32 val)
326 guint16 *__lui_addiu = (guint16*)(void *)(ip);
328 #if 0
329 printf ("patch_lui_addiu ip=0x%08x (0x%08x, 0x%08x) to point to 0x%08x\n",
330 ip, ((guint32 *)ip)[0], ((guint32 *)ip)[1], val);
331 fflush (stdout);
332 #endif
333 if (((guint32)(val)) & (1 << 15))
334 __lui_addiu [MINI_LS_WORD_IDX] = ((((guint32)(val)) >> 16) & 0xffff) + 1;
335 else
336 __lui_addiu [MINI_LS_WORD_IDX] = (((guint32)(val)) >> 16) & 0xffff;
337 __lui_addiu [MINI_LS_WORD_IDX + 2] = ((guint32)(val)) & 0xffff;
338 mono_arch_flush_icache ((guint8 *)ip, 8);
341 guint32 trap_target;
342 void
343 mips_patch (guint32 *code, guint32 target)
345 guint32 ins = *code;
346 guint32 op = ins >> 26;
347 guint32 diff, offset;
349 g_assert (trap_target != target);
350 //printf ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
351 switch (op) {
352 case 0x00: /* jr ra */
353 if (ins == 0x3e00008)
354 break;
355 g_assert_not_reached ();
356 break;
357 case 0x02: /* j */
358 case 0x03: /* jal */
359 g_assert (!(target & 0x03));
360 g_assert ((target & 0xfc000000) == (((guint32)code) & 0xfc000000));
361 ins = (ins & 0xfc000000) | (((target) >> 2) & 0x03ffffff);
362 *code = ins;
363 mono_arch_flush_icache ((guint8 *)code, 4);
364 break;
365 case 0x01: /* BLTZ */
366 case 0x04: /* BEQ */
367 case 0x05: /* BNE */
368 case 0x06: /* BLEZ */
369 case 0x07: /* BGTZ */
370 case 0x11: /* bc1t */
371 diff = target - (guint32)(code + 1);
372 g_assert (((diff & 0x0003ffff) == diff) || ((diff | 0xfffc0000) == diff));
373 g_assert (!(diff & 0x03));
374 offset = ((gint32)diff) >> 2;
375 if (((int)offset) != ((int)(short)offset))
376 g_assert (((int)offset) == ((int)(short)offset));
377 ins = (ins & 0xffff0000) | (offset & 0x0000ffff);
378 *code = ins;
379 mono_arch_flush_icache ((guint8 *)code, 4);
380 break;
381 case 0x0f: /* LUI / ADDIU pair */
382 g_assert ((code[1] >> 26) == 0x9);
383 patch_lui_addiu (code, target);
384 mono_arch_flush_icache ((guint8 *)code, 8);
385 break;
387 default:
388 printf ("unknown op 0x%02x (0x%08x) @ %p\n", op, ins, code);
389 g_assert_not_reached ();
393 static void mono_arch_compute_omit_fp (MonoCompile *cfg);
395 const char*
396 mono_arch_regname (int reg) {
397 #if _MIPS_SIM == _ABIO32
398 static const char * rnames[] = {
399 "zero", "at", "v0", "v1",
400 "a0", "a1", "a2", "a3",
401 "t0", "t1", "t2", "t3",
402 "t4", "t5", "t6", "t7",
403 "s0", "s1", "s2", "s3",
404 "s4", "s5", "s6", "s7",
405 "t8", "t9", "k0", "k1",
406 "gp", "sp", "fp", "ra"
408 #elif _MIPS_SIM == _ABIN32
409 static const char * rnames[] = {
410 "zero", "at", "v0", "v1",
411 "a0", "a1", "a2", "a3",
412 "a4", "a5", "a6", "a7",
413 "t0", "t1", "t2", "t3",
414 "s0", "s1", "s2", "s3",
415 "s4", "s5", "s6", "s7",
416 "t8", "t9", "k0", "k1",
417 "gp", "sp", "fp", "ra"
419 #endif
420 if (reg >= 0 && reg < 32)
421 return rnames [reg];
422 return "unknown";
425 const char*
426 mono_arch_fregname (int reg) {
427 static const char * rnames[] = {
428 "f0", "f1", "f2", "f3",
429 "f4", "f5", "f6", "f7",
430 "f8", "f9", "f10", "f11",
431 "f12", "f13", "f14", "f15",
432 "f16", "f17", "f18", "f19",
433 "f20", "f21", "f22", "f23",
434 "f24", "f25", "f26", "f27",
435 "f28", "f29", "f30", "f31"
437 if (reg >= 0 && reg < 32)
438 return rnames [reg];
439 return "unknown";
442 /* this function overwrites at */
443 static guint8*
444 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
446 /* XXX write a loop, not an unrolled loop */
447 while (size > 0) {
448 mips_lw (code, mips_at, sreg, soffset);
449 mips_sw (code, mips_at, dreg, doffset);
450 size -= 4;
451 soffset += 4;
452 doffset += 4;
454 return code;
458 * mono_arch_get_argument_info:
459 * @csig: a method signature
460 * @param_count: the number of parameters to consider
461 * @arg_info: an array to store the result infos
463 * Gathers information on parameters such as size, alignment and
464 * padding. arg_info should be large enought to hold param_count + 1 entries.
466 * Returns the size of the activation frame.
469 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
471 int k, frame_size = 0;
472 guint32 size, align, pad;
473 int offset = 0;
475 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
476 frame_size += sizeof (target_mgreg_t);
477 offset += 4;
480 arg_info [0].offset = offset;
482 if (csig->hasthis) {
483 frame_size += sizeof (target_mgreg_t);
484 offset += 4;
487 arg_info [0].size = frame_size;
489 for (k = 0; k < param_count; k++) {
490 size = mini_type_stack_size_full (csig->params [k], &align, csig->pinvoke);
492 /* ignore alignment for now */
493 align = 1;
495 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
496 arg_info [k].pad = pad;
497 frame_size += size;
498 arg_info [k + 1].pad = 0;
499 arg_info [k + 1].size = size;
500 offset += pad;
501 arg_info [k + 1].offset = offset;
502 offset += size;
505 align = MONO_ARCH_FRAME_ALIGNMENT;
506 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
507 arg_info [k].pad = pad;
509 return frame_size;
512 /* The delegate object plus 3 params */
513 #define MAX_ARCH_DELEGATE_PARAMS (4 - 1)
515 static guint8*
516 get_delegate_invoke_impl (MonoTrampInfo **info, gboolean has_target, gboolean param_count)
518 guint8 *code, *start;
520 if (has_target) {
521 start = code = mono_global_codeman_reserve (16);
523 /* Replace the this argument with the target */
524 mips_lw (code, mips_temp, mips_a0, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
525 mips_lw (code, mips_a0, mips_a0, MONO_STRUCT_OFFSET (MonoDelegate, target));
526 mips_jr (code, mips_temp);
527 mips_nop (code);
529 g_assert ((code - start) <= 16);
531 mono_arch_flush_icache (start, 16);
532 MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_DELEGATE_INVOKE, NULL));
533 } else {
534 int size, i;
536 size = 16 + param_count * 4;
537 start = code = mono_global_codeman_reserve (size);
539 mips_lw (code, mips_temp, mips_a0, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
540 /* slide down the arguments */
541 for (i = 0; i < param_count; ++i) {
542 mips_move (code, mips_a0 + i, mips_a0 + i + 1);
544 mips_jr (code, mips_temp);
545 mips_nop (code);
547 g_assert ((code - start) <= size);
549 mono_arch_flush_icache (start, size);
550 MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_DELEGATE_INVOKE, NULL));
553 if (has_target) {
554 *info = mono_tramp_info_create ("delegate_invoke_impl_has_target", start, code - start, NULL, NULL);
555 } else {
556 char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", param_count);
557 *info = mono_tramp_info_create (name, start, code - start, NULL, NULL);
558 g_free (name);
561 return start;
565 * mono_arch_get_delegate_invoke_impls:
567 * Return a list of MonoAotTrampInfo structures for the delegate invoke impl
568 * trampolines.
570 GSList*
571 mono_arch_get_delegate_invoke_impls (void)
573 GSList *res = NULL;
574 MonoTrampInfo *info;
575 int i;
577 get_delegate_invoke_impl (&info, TRUE, 0);
578 res = g_slist_prepend (res, info);
580 for (i = 0; i <= MAX_ARCH_DELEGATE_PARAMS; ++i) {
581 get_delegate_invoke_impl (&info, FALSE, i);
582 res = g_slist_prepend (res, info);
585 return res;
588 gpointer
589 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
591 guint8 *code, *start;
593 /* FIXME: Support more cases */
594 if (MONO_TYPE_ISSTRUCT (sig->ret))
595 return NULL;
597 if (has_target) {
598 static guint8* cached = NULL;
599 mono_mini_arch_lock ();
600 if (cached) {
601 mono_mini_arch_unlock ();
602 return cached;
605 if (mono_ee_features.use_aot_trampolines) {
606 start = mono_aot_get_trampoline ("delegate_invoke_impl_has_target");
607 } else {
608 MonoTrampInfo *info;
609 start = get_delegate_invoke_impl (&info, TRUE, 0);
610 mono_tramp_info_register (info, NULL);
612 cached = start;
613 mono_mini_arch_unlock ();
614 return cached;
615 } else {
616 static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
617 int i;
619 if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
620 return NULL;
621 for (i = 0; i < sig->param_count; ++i)
622 if (!mono_is_regsize_var (sig->params [i]))
623 return NULL;
625 mono_mini_arch_lock ();
626 code = cache [sig->param_count];
627 if (code) {
628 mono_mini_arch_unlock ();
629 return code;
632 if (mono_ee_features.use_aot_trampolines) {
633 char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", sig->param_count);
634 start = mono_aot_get_trampoline (name);
635 g_free (name);
636 } else {
637 MonoTrampInfo *info;
638 start = get_delegate_invoke_impl (&info, FALSE, sig->param_count);
639 mono_tramp_info_register (info, NULL);
641 cache [sig->param_count] = start;
642 mono_mini_arch_unlock ();
643 return start;
646 return NULL;
649 gpointer
650 mono_arch_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method, int offset, gboolean load_imt_reg)
652 return NULL;
655 gpointer
656 mono_arch_get_this_arg_from_call (host_mgreg_t *regs, guint8 *code)
658 g_assert(regs);
659 return (gpointer)regs [mips_a0];
663 * Initialize the cpu to execute managed code.
665 void
666 mono_arch_cpu_init (void)
668 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
669 little_endian = 1;
670 ls_word_idx = 0;
671 ms_word_idx = 1;
672 #else
673 ls_word_idx = 1;
674 ms_word_idx = 0;
675 #endif
677 ls_word_offset = ls_word_idx * 4;
678 ms_word_offset = ms_word_idx * 4;
682 * Initialize architecture specific code.
684 void
685 mono_arch_init (void)
687 mono_os_mutex_init_recursive (&mini_arch_mutex);
689 ss_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ, MONO_MEM_ACCOUNT_OTHER);
690 bp_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ, MONO_MEM_ACCOUNT_OTHER);
691 mono_mprotect (bp_trigger_page, mono_pagesize (), 0);
695 * Cleanup architecture specific code.
697 void
698 mono_arch_cleanup (void)
700 mono_os_mutex_destroy (&mini_arch_mutex);
703 gboolean
704 mono_arch_have_fast_tls (void)
706 return FALSE;
710 * This function returns the optimizations supported on this cpu.
712 guint32
713 mono_arch_cpu_optimizations (guint32 *exclude_mask)
715 guint32 opts = 0;
717 /* no mips-specific optimizations yet */
718 *exclude_mask = 0;
719 return opts;
723 * This function test for all SIMD functions supported.
725 * Returns a bitmask corresponding to all supported versions.
728 guint32
729 mono_arch_cpu_enumerate_simd_versions (void)
731 /* SIMD is currently unimplemented */
732 return 0;
735 GList *
736 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
738 GList *vars = NULL;
739 int i;
741 for (i = 0; i < cfg->num_varinfo; i++) {
742 MonoInst *ins = cfg->varinfo [i];
743 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
745 /* unused vars */
746 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
747 continue;
749 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
750 continue;
752 /* we can only allocate 32 bit values */
753 if (mono_is_regsize_var (ins->inst_vtype)) {
754 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
755 g_assert (i == vmv->idx);
756 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
760 return vars;
763 GList *
764 mono_arch_get_global_int_regs (MonoCompile *cfg)
766 GList *regs = NULL;
768 regs = g_list_prepend (regs, (gpointer)mips_s0);
769 regs = g_list_prepend (regs, (gpointer)mips_s1);
770 regs = g_list_prepend (regs, (gpointer)mips_s2);
771 regs = g_list_prepend (regs, (gpointer)mips_s3);
772 regs = g_list_prepend (regs, (gpointer)mips_s4);
773 //regs = g_list_prepend (regs, (gpointer)mips_s5);
774 regs = g_list_prepend (regs, (gpointer)mips_s6);
775 regs = g_list_prepend (regs, (gpointer)mips_s7);
777 return regs;
781 * mono_arch_regalloc_cost:
783 * Return the cost, in number of memory references, of the action of
784 * allocating the variable VMV into a register during global register
785 * allocation.
787 guint32
788 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
790 /* FIXME: */
791 return 2;
794 static void
795 args_onto_stack (CallInfo *info)
797 g_assert (!info->on_stack);
798 g_assert (info->stack_size <= MIPS_STACK_PARAM_OFFSET);
799 info->on_stack = TRUE;
800 info->stack_size = MIPS_STACK_PARAM_OFFSET;
803 #if _MIPS_SIM == _ABIO32
805 * O32 calling convention version
808 static void
809 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
810 /* First, see if we need to drop onto the stack */
811 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
812 args_onto_stack (info);
814 /* Now, place the argument */
815 if (info->on_stack) {
816 ainfo->storage = ArgOnStack;
817 ainfo->reg = mips_sp; /* in the caller */
818 ainfo->offset = info->stack_size;
820 else {
821 ainfo->storage = ArgInIReg;
822 ainfo->reg = info->gr;
823 info->gr += 1;
824 info->gr_passed = TRUE;
826 info->stack_size += 4;
829 static void
830 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
831 /* First, see if we need to drop onto the stack */
832 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
833 args_onto_stack (info);
835 /* Now, place the argument */
836 if (info->on_stack) {
837 g_assert (info->stack_size % 4 == 0);
838 info->stack_size += (info->stack_size % 8);
840 ainfo->storage = ArgOnStack;
841 ainfo->reg = mips_sp; /* in the caller */
842 ainfo->offset = info->stack_size;
844 else {
845 // info->gr must be a0 or a2
846 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
847 g_assert(info->gr <= MIPS_LAST_ARG_REG);
849 ainfo->storage = ArgInIReg;
850 ainfo->reg = info->gr;
851 info->gr += 2;
852 info->gr_passed = TRUE;
854 info->stack_size += 8;
857 static void
858 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
859 /* First, see if we need to drop onto the stack */
860 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
861 args_onto_stack (info);
863 /* Now, place the argument */
864 if (info->on_stack) {
865 ainfo->storage = ArgOnStack;
866 ainfo->reg = mips_sp; /* in the caller */
867 ainfo->offset = info->stack_size;
869 else {
870 /* Only use FP regs for args if no int args passed yet */
871 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
872 ainfo->storage = ArgInFReg;
873 ainfo->reg = info->fr;
874 /* Even though it's a single-precision float, it takes up two FP regs */
875 info->fr += 2;
876 /* FP and GP slots do not overlap */
877 info->gr += 1;
879 else {
880 /* Passing single-precision float arg in a GP register
881 * such as: func (0, 1.0, 2, 3);
882 * In this case, only one 'gr' register is consumed.
884 ainfo->storage = ArgInIReg;
885 ainfo->reg = info->gr;
887 info->gr += 1;
888 info->gr_passed = TRUE;
891 info->stack_size += 4;
894 static void
895 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
896 /* First, see if we need to drop onto the stack */
897 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
898 args_onto_stack (info);
900 /* Now, place the argument */
901 if (info->on_stack) {
902 g_assert(info->stack_size % 4 == 0);
903 info->stack_size += (info->stack_size % 8);
905 ainfo->storage = ArgOnStack;
906 ainfo->reg = mips_sp; /* in the caller */
907 ainfo->offset = info->stack_size;
909 else {
910 /* Only use FP regs for args if no int args passed yet */
911 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
912 ainfo->storage = ArgInFReg;
913 ainfo->reg = info->fr;
914 info->fr += 2;
915 /* FP and GP slots do not overlap */
916 info->gr += 2;
918 else {
919 // info->gr must be a0 or a2
920 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
921 g_assert(info->gr <= MIPS_LAST_ARG_REG);
923 ainfo->storage = ArgInIReg;
924 ainfo->reg = info->gr;
925 info->gr += 2;
926 info->gr_passed = TRUE;
929 info->stack_size += 8;
931 #elif _MIPS_SIM == _ABIN32
933 * N32 calling convention version
936 static void
937 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
938 /* First, see if we need to drop onto the stack */
939 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
940 args_onto_stack (info);
942 /* Now, place the argument */
943 if (info->on_stack) {
944 ainfo->storage = ArgOnStack;
945 ainfo->reg = mips_sp; /* in the caller */
946 ainfo->offset = info->stack_size;
947 info->stack_size += SIZEOF_REGISTER;
949 else {
950 ainfo->storage = ArgInIReg;
951 ainfo->reg = info->gr;
952 info->gr += 1;
953 info->gr_passed = TRUE;
957 static void
958 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
959 /* First, see if we need to drop onto the stack */
960 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
961 args_onto_stack (info);
963 /* Now, place the argument */
964 if (info->on_stack) {
965 g_assert (info->stack_size % 4 == 0);
966 info->stack_size += (info->stack_size % 8);
968 ainfo->storage = ArgOnStack;
969 ainfo->reg = mips_sp; /* in the caller */
970 ainfo->offset = info->stack_size;
971 info->stack_size += SIZEOF_REGISTER;
973 else {
974 g_assert (info->gr <= MIPS_LAST_ARG_REG);
976 ainfo->storage = ArgInIReg;
977 ainfo->reg = info->gr;
978 info->gr += 1;
979 info->gr_passed = TRUE;
983 static void
984 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
985 /* First, see if we need to drop onto the stack */
986 if (!info->on_stack) {
987 if (info->gr > MIPS_LAST_ARG_REG)
988 args_onto_stack (info);
989 else if (info->fr > MIPS_LAST_FPARG_REG)
990 args_onto_stack (info);
993 /* Now, place the argument */
994 if (info->on_stack) {
995 ainfo->storage = ArgOnStack;
996 ainfo->reg = mips_sp; /* in the caller */
997 ainfo->offset = info->stack_size;
998 info->stack_size += FREG_SIZE;
1000 else {
1001 ainfo->storage = ArgInFReg;
1002 ainfo->reg = info->fr;
1003 info->fr += 1;
1004 /* FP and GP slots do not overlap */
1005 info->gr += 1;
1009 static void
1010 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
1011 /* First, see if we need to drop onto the stack */
1012 if (!info->on_stack) {
1013 if (info->gr > MIPS_LAST_ARG_REG)
1014 args_onto_stack (info);
1015 else if (info->fr > MIPS_LAST_FPARG_REG)
1016 args_onto_stack (info);
1019 /* Now, place the argument */
1020 if (info->on_stack) {
1021 g_assert(info->stack_size % 4 == 0);
1022 info->stack_size += (info->stack_size % 8);
1024 ainfo->storage = ArgOnStack;
1025 ainfo->reg = mips_sp; /* in the caller */
1026 ainfo->offset = info->stack_size;
1027 info->stack_size += FREG_SIZE;
1029 else {
1030 ainfo->storage = ArgInFReg;
1031 ainfo->reg = info->fr;
1032 info->fr += 1;
1033 /* FP and GP slots do not overlap */
1034 info->gr += 1;
1037 #endif
1039 static CallInfo*
1040 get_call_info (MonoMemPool *mp, MonoMethodSignature *sig)
1042 guint i;
1043 int n = sig->hasthis + sig->param_count;
1044 int pstart;
1045 MonoType* simpletype;
1046 CallInfo *cinfo;
1047 gboolean is_pinvoke = sig->pinvoke;
1049 if (mp)
1050 cinfo = mono_mempool_alloc0 (mp, sizeof (CallInfo) + (sizeof (ArgInfo) * n));
1051 else
1052 cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
1054 cinfo->fr = MIPS_FIRST_FPARG_REG;
1055 cinfo->gr = MIPS_FIRST_ARG_REG;
1056 cinfo->stack_size = 0;
1058 DEBUG(printf("calculate_sizes\n"));
1060 cinfo->vtype_retaddr = MONO_TYPE_ISSTRUCT (sig->ret) ? TRUE : FALSE;
1061 pstart = 0;
1062 n = 0;
1063 #if 0
1064 /* handle returning a struct */
1065 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1066 cinfo->struct_ret = cinfo->gr;
1067 add_int32_arg (cinfo, &cinfo->ret);
1070 if (sig->hasthis) {
1071 add_int32_arg (cinfo, cinfo->args + n);
1072 n++;
1074 #else
1076 * To simplify get_this_arg_reg () and LLVM integration, emit the vret arg after
1077 * the first argument, allowing 'this' to be always passed in the first arg reg.
1078 * Also do this if the first argument is a reference type, since virtual calls
1079 * are sometimes made using calli without sig->hasthis set, like in the delegate
1080 * invoke wrappers.
1082 if (cinfo->vtype_retaddr && !is_pinvoke && (sig->hasthis || (sig->param_count > 0 && MONO_TYPE_IS_REFERENCE (mini_get_underlying_type (sig->params [0]))))) {
1083 if (sig->hasthis) {
1084 add_int32_arg (cinfo, cinfo->args + n);
1085 n ++;
1086 } else {
1087 add_int32_arg (cinfo, cinfo->args + sig->hasthis);
1088 pstart = 1;
1089 n ++;
1091 add_int32_arg (cinfo, &cinfo->ret);
1092 cinfo->struct_ret = cinfo->ret.reg;
1093 } else {
1094 /* this */
1095 if (sig->hasthis) {
1096 add_int32_arg (cinfo, cinfo->args + n);
1097 n ++;
1100 if (cinfo->vtype_retaddr) {
1101 add_int32_arg (cinfo, &cinfo->ret);
1102 cinfo->struct_ret = cinfo->ret.reg;
1105 #endif
1107 DEBUG(printf("params: %d\n", sig->param_count));
1108 for (i = pstart; i < sig->param_count; ++i) {
1109 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1110 /* Prevent implicit arguments and sig_cookie from
1111 being passed in registers */
1112 args_onto_stack (cinfo);
1113 /* Emit the signature cookie just before the implicit arguments */
1114 add_int32_arg (cinfo, &cinfo->sig_cookie);
1116 DEBUG(printf("param %d: ", i));
1117 simpletype = mini_get_underlying_type (sig->params [i]);
1118 switch (simpletype->type) {
1119 case MONO_TYPE_I1:
1120 case MONO_TYPE_U1:
1121 DEBUG(printf("1 byte\n"));
1122 cinfo->args [n].size = 1;
1123 add_int32_arg (cinfo, &cinfo->args[n]);
1124 n++;
1125 break;
1126 case MONO_TYPE_I2:
1127 case MONO_TYPE_U2:
1128 DEBUG(printf("2 bytes\n"));
1129 cinfo->args [n].size = 2;
1130 add_int32_arg (cinfo, &cinfo->args[n]);
1131 n++;
1132 break;
1133 case MONO_TYPE_I4:
1134 case MONO_TYPE_U4:
1135 DEBUG(printf("4 bytes\n"));
1136 cinfo->args [n].size = 4;
1137 add_int32_arg (cinfo, &cinfo->args[n]);
1138 n++;
1139 break;
1140 case MONO_TYPE_I:
1141 case MONO_TYPE_U:
1142 case MONO_TYPE_PTR:
1143 case MONO_TYPE_FNPTR:
1144 case MONO_TYPE_OBJECT:
1145 cinfo->args [n].size = sizeof (target_mgreg_t);
1146 add_int32_arg (cinfo, &cinfo->args[n]);
1147 n++;
1148 break;
1149 case MONO_TYPE_GENERICINST:
1150 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1151 cinfo->args [n].size = sizeof (target_mgreg_t);
1152 add_int32_arg (cinfo, &cinfo->args[n]);
1153 n++;
1154 break;
1156 /* Fall through */
1157 case MONO_TYPE_TYPEDBYREF:
1158 case MONO_TYPE_VALUETYPE: {
1159 int j;
1160 int nwords = 0;
1161 int has_offset = FALSE;
1162 ArgInfo dummy_arg;
1163 gint size, alignment;
1164 MonoClass *klass;
1166 if (simpletype->type == MONO_TYPE_TYPEDBYREF) {
1167 size = MONO_ABI_SIZEOF (MonoTypedRef);
1168 alignment = sizeof (target_mgreg_t);
1169 } else {
1170 klass = mono_class_from_mono_type_internal (sig->params [i]);
1171 if (is_pinvoke)
1172 size = mono_class_native_size (klass, NULL);
1173 else
1174 size = mono_class_value_size (klass, NULL);
1175 alignment = mono_class_min_align (klass);
1177 #if MIPS_PASS_STRUCTS_BY_VALUE
1178 /* Need to do alignment if struct contains long or double */
1179 if (alignment > 4) {
1180 /* Drop onto stack *before* looking at
1181 stack_size, if required. */
1182 if (!cinfo->on_stack && cinfo->gr > MIPS_LAST_ARG_REG)
1183 args_onto_stack (cinfo);
1184 if (cinfo->stack_size & (alignment - 1)) {
1185 add_int32_arg (cinfo, &dummy_arg);
1187 g_assert (!(cinfo->stack_size & (alignment - 1)));
1190 #if 0
1191 g_printf ("valuetype struct size=%d offset=%d align=%d\n",
1192 mono_class_native_size (sig->params [i]->data.klass, NULL),
1193 cinfo->stack_size, alignment);
1194 #endif
1195 nwords = (size + sizeof (target_mgreg_t) -1 ) / sizeof (target_mgreg_t);
1196 g_assert (cinfo->args [n].size == 0);
1197 g_assert (cinfo->args [n].vtsize == 0);
1198 for (j = 0; j < nwords; ++j) {
1199 if (j == 0) {
1200 add_int32_arg (cinfo, &cinfo->args [n]);
1201 if (cinfo->on_stack)
1202 has_offset = TRUE;
1203 } else {
1204 add_int32_arg (cinfo, &dummy_arg);
1205 if (!has_offset && cinfo->on_stack) {
1206 cinfo->args [n].offset = dummy_arg.offset;
1207 has_offset = TRUE;
1210 if (cinfo->on_stack)
1211 cinfo->args [n].vtsize += 1;
1212 else
1213 cinfo->args [n].size += 1;
1215 //g_printf ("\tstack_size=%d vtsize=%d\n", cinfo->args [n].size, cinfo->args[n].vtsize);
1216 cinfo->args [n].storage = ArgStructByVal;
1217 #else
1218 add_int32_arg (cinfo, &cinfo->args[n]);
1219 cinfo->args [n].storage = ArgStructByAddr;
1220 #endif
1221 n++;
1222 break;
1224 case MONO_TYPE_U8:
1225 case MONO_TYPE_I8:
1226 DEBUG(printf("8 bytes\n"));
1227 cinfo->args [n].size = 8;
1228 add_int64_arg (cinfo, &cinfo->args[n]);
1229 n++;
1230 break;
1231 case MONO_TYPE_R4:
1232 DEBUG(printf("R4\n"));
1233 cinfo->args [n].size = 4;
1234 add_float32_arg (cinfo, &cinfo->args[n]);
1235 n++;
1236 break;
1237 case MONO_TYPE_R8:
1238 DEBUG(printf("R8\n"));
1239 cinfo->args [n].size = 8;
1240 add_float64_arg (cinfo, &cinfo->args[n]);
1241 n++;
1242 break;
1243 default:
1244 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
1248 /* Handle the case where there are no implicit arguments */
1249 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1250 /* Prevent implicit arguments and sig_cookie from
1251 being passed in registers */
1252 args_onto_stack (cinfo);
1253 /* Emit the signature cookie just before the implicit arguments */
1254 add_int32_arg (cinfo, &cinfo->sig_cookie);
1258 simpletype = mini_get_underlying_type (sig->ret);
1259 switch (simpletype->type) {
1260 case MONO_TYPE_I1:
1261 case MONO_TYPE_U1:
1262 case MONO_TYPE_I2:
1263 case MONO_TYPE_U2:
1264 case MONO_TYPE_I4:
1265 case MONO_TYPE_U4:
1266 case MONO_TYPE_I:
1267 case MONO_TYPE_U:
1268 case MONO_TYPE_PTR:
1269 case MONO_TYPE_FNPTR:
1270 case MONO_TYPE_OBJECT:
1271 cinfo->ret.reg = mips_v0;
1272 break;
1273 case MONO_TYPE_U8:
1274 case MONO_TYPE_I8:
1275 cinfo->ret.reg = mips_v0;
1276 break;
1277 case MONO_TYPE_R4:
1278 case MONO_TYPE_R8:
1279 cinfo->ret.reg = mips_f0;
1280 cinfo->ret.storage = ArgInFReg;
1281 break;
1282 case MONO_TYPE_GENERICINST:
1283 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1284 cinfo->ret.reg = mips_v0;
1285 break;
1287 break;
1288 case MONO_TYPE_VALUETYPE:
1289 case MONO_TYPE_TYPEDBYREF:
1290 break;
1291 case MONO_TYPE_VOID:
1292 break;
1293 default:
1294 g_error ("Can't handle as return value 0x%x", sig->ret->type);
1298 /* align stack size to 16 */
1299 cinfo->stack_size = (cinfo->stack_size + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1301 cinfo->stack_usage = cinfo->stack_size;
1302 return cinfo;
1305 static gboolean
1306 debug_omit_fp (void)
1308 #if 0
1309 return mono_debug_count ();
1310 #else
1311 return TRUE;
1312 #endif
1316 * mono_arch_compute_omit_fp:
1317 * Determine whether the frame pointer can be eliminated.
1319 static void
1320 mono_arch_compute_omit_fp (MonoCompile *cfg)
1322 MonoMethodSignature *sig;
1323 MonoMethodHeader *header;
1324 int i, locals_size;
1325 CallInfo *cinfo;
1327 if (cfg->arch.omit_fp_computed)
1328 return;
1330 header = cfg->header;
1332 sig = mono_method_signature_internal (cfg->method);
1334 if (!cfg->arch.cinfo)
1335 cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
1336 cinfo = cfg->arch.cinfo;
1339 * FIXME: Remove some of the restrictions.
1341 cfg->arch.omit_fp = TRUE;
1342 cfg->arch.omit_fp_computed = TRUE;
1344 if (cfg->disable_omit_fp)
1345 cfg->arch.omit_fp = FALSE;
1346 if (!debug_omit_fp ())
1347 cfg->arch.omit_fp = FALSE;
1348 if (cfg->method->save_lmf)
1349 cfg->arch.omit_fp = FALSE;
1350 if (cfg->flags & MONO_CFG_HAS_ALLOCA)
1351 cfg->arch.omit_fp = FALSE;
1352 if (header->num_clauses)
1353 cfg->arch.omit_fp = FALSE;
1354 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
1355 cfg->arch.omit_fp = FALSE;
1357 * On MIPS, fp points to the bottom of the frame, so it can be eliminated even if
1358 * there are stack arguments.
1361 if (cinfo->stack_usage)
1362 cfg->arch.omit_fp = FALSE;
1365 locals_size = 0;
1366 for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
1367 MonoInst *ins = cfg->varinfo [i];
1368 int ialign;
1370 locals_size += mono_type_size (ins->inst_vtype, &ialign);
1373 //printf ("D: %s %d\n", cfg->method->name, cfg->arch.omit_fp);
1377 * Set var information according to the calling convention. mips version.
1378 * The locals var stuff should most likely be split in another method.
1380 void
1381 mono_arch_allocate_vars (MonoCompile *cfg)
1383 MonoMethodSignature *sig;
1384 MonoMethodHeader *header;
1385 MonoInst *inst;
1386 int i, offset, size, align, curinst;
1387 int frame_reg = mips_sp;
1388 guint32 iregs_to_save = 0;
1389 #if SAVE_FP_REGS
1390 guint32 fregs_to_restore;
1391 #endif
1392 CallInfo *cinfo;
1394 sig = mono_method_signature_internal (cfg->method);
1396 if (!cfg->arch.cinfo)
1397 cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
1398 cinfo = cfg->arch.cinfo;
1400 mono_arch_compute_omit_fp (cfg);
1402 /* spill down, we'll fix it in a separate pass */
1403 // cfg->flags |= MONO_CFG_HAS_SPILLUP;
1405 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1406 * call convs needs to be handled this way.
1408 if (cfg->flags & MONO_CFG_HAS_VARARGS)
1409 cfg->param_area = MAX (cfg->param_area, sizeof (target_mgreg_t)*8);
1411 /* gtk-sharp and other broken code will dllimport vararg functions even with
1412 * non-varargs signatures. Since there is little hope people will get this right
1413 * we assume they won't.
1415 if (cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1416 cfg->param_area = MAX (cfg->param_area, sizeof (target_mgreg_t)*8);
1418 /* a0-a3 always present */
1419 cfg->param_area = MAX (cfg->param_area, MIPS_STACK_PARAM_OFFSET);
1421 header = cfg->header;
1423 if (cfg->arch.omit_fp)
1424 frame_reg = mips_sp;
1425 else
1426 frame_reg = mips_fp;
1427 cfg->frame_reg = frame_reg;
1428 if (frame_reg != mips_sp) {
1429 cfg->used_int_regs |= 1 << frame_reg;
1432 offset = 0;
1433 curinst = 0;
1434 if (!MONO_TYPE_ISSTRUCT (sig->ret)) {
1435 /* FIXME: handle long and FP values */
1436 switch (mini_get_underlying_type (sig->ret)->type) {
1437 case MONO_TYPE_VOID:
1438 break;
1439 case MONO_TYPE_R4:
1440 case MONO_TYPE_R8:
1441 cfg->ret->opcode = OP_REGVAR;
1442 cfg->ret->inst_c0 = cfg->ret->dreg = mips_f0;
1443 break;
1444 default:
1445 cfg->ret->opcode = OP_REGVAR;
1446 cfg->ret->inst_c0 = mips_v0;
1447 break;
1450 /* Space for outgoing parameters, including a0-a3 */
1451 offset += cfg->param_area;
1453 /* Now handle the local variables */
1455 curinst = cfg->locals_start;
1456 for (i = curinst; i < cfg->num_varinfo; ++i) {
1457 inst = cfg->varinfo [i];
1458 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
1459 continue;
1461 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
1462 * pinvoke wrappers when they call functions returning structure
1464 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
1465 size = mono_class_native_size (mono_class_from_mono_type_internal (inst->inst_vtype), (unsigned int *) &align);
1466 else
1467 size = mono_type_size (inst->inst_vtype, &align);
1469 offset += align - 1;
1470 offset &= ~(align - 1);
1471 inst->inst_offset = offset;
1472 inst->opcode = OP_REGOFFSET;
1473 inst->inst_basereg = frame_reg;
1474 offset += size;
1475 // g_print ("allocating local %d to %d\n", i, inst->inst_offset);
1478 /* Space for LMF (if needed) */
1479 if (cfg->method->save_lmf) {
1480 /* align the offset to 16 bytes */
1481 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1482 cfg->arch.lmf_offset = offset;
1483 offset += sizeof (MonoLMF);
1486 if (sig->call_convention == MONO_CALL_VARARG) {
1487 size = 4;
1488 align = 4;
1490 /* Allocate a local slot to hold the sig cookie address */
1491 offset += align - 1;
1492 offset &= ~(align - 1);
1493 cfg->sig_cookie = offset;
1494 offset += size;
1497 offset += SIZEOF_REGISTER - 1;
1498 offset &= ~(SIZEOF_REGISTER - 1);
1500 /* Space for saved registers */
1501 cfg->arch.iregs_offset = offset;
1502 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
1503 if (iregs_to_save) {
1504 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
1505 if (iregs_to_save & (1 << i)) {
1506 offset += SIZEOF_REGISTER;
1511 /* saved float registers */
1512 #if SAVE_FP_REGS
1513 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
1514 if (fregs_to_restore) {
1515 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
1516 if (fregs_to_restore & (1 << i)) {
1517 offset += sizeof(double);
1521 #endif
1523 #if _MIPS_SIM == _ABIO32
1524 /* Now add space for saving the ra */
1525 offset += TARGET_SIZEOF_VOID_P;
1527 /* change sign? */
1528 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1529 cfg->stack_offset = offset;
1530 cfg->arch.local_alloc_offset = cfg->stack_offset;
1531 #endif
1534 * Now allocate stack slots for the int arg regs (a0 - a3)
1535 * On MIPS o32, these are just above the incoming stack pointer
1536 * Even if the arg has been assigned to a regvar, it gets a stack slot
1539 /* Return struct-by-value results in a hidden first argument */
1540 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1541 cfg->vret_addr->opcode = OP_REGOFFSET;
1542 cfg->vret_addr->inst_c0 = mips_a0;
1543 cfg->vret_addr->inst_offset = offset;
1544 cfg->vret_addr->inst_basereg = frame_reg;
1545 offset += SIZEOF_REGISTER;
1548 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
1549 inst = cfg->args [i];
1550 if (inst->opcode != OP_REGVAR) {
1551 MonoType *arg_type;
1553 if (sig->hasthis && (i == 0))
1554 arg_type = mono_get_object_type ();
1555 else
1556 arg_type = sig->params [i - sig->hasthis];
1558 inst->opcode = OP_REGOFFSET;
1559 size = mono_type_size (arg_type, &align);
1561 if (size < SIZEOF_REGISTER) {
1562 size = SIZEOF_REGISTER;
1563 align = SIZEOF_REGISTER;
1565 inst->inst_basereg = frame_reg;
1566 offset = (offset + align - 1) & ~(align - 1);
1567 inst->inst_offset = offset;
1568 offset += size;
1569 if (cfg->verbose_level > 1)
1570 printf ("allocating param %d to fp[%d]\n", i, inst->inst_offset);
1572 else {
1573 #if _MIPS_SIM == _ABIO32
1574 /* o32: Even a0-a3 get stack slots */
1575 size = SIZEOF_REGISTER;
1576 align = SIZEOF_REGISTER;
1577 inst->inst_basereg = frame_reg;
1578 offset = (offset + align - 1) & ~(align - 1);
1579 inst->inst_offset = offset;
1580 offset += size;
1581 if (cfg->verbose_level > 1)
1582 printf ("allocating param %d to fp[%d]\n", i, inst->inst_offset);
1583 #endif
1586 #if _MIPS_SIM == _ABIN32
1587 /* Now add space for saving the ra */
1588 offset += TARGET_SIZEOF_VOID_P;
1590 /* change sign? */
1591 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1592 cfg->stack_offset = offset;
1593 cfg->arch.local_alloc_offset = cfg->stack_offset;
1594 #endif
1597 void
1598 mono_arch_create_vars (MonoCompile *cfg)
1600 MonoMethodSignature *sig;
1602 sig = mono_method_signature_internal (cfg->method);
1604 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1605 cfg->vret_addr = mono_compile_create_var (cfg, mono_get_int_type (), OP_ARG);
1606 if (G_UNLIKELY (cfg->verbose_level > 1)) {
1607 printf ("vret_addr = ");
1608 mono_print_ins (cfg->vret_addr);
1613 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1614 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1618 * take the arguments and generate the arch-specific
1619 * instructions to properly call the function in call.
1620 * This includes pushing, moving arguments to the right register
1621 * etc.
1622 * Issue: who does the spilling if needed, and when?
1624 static void
1625 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1627 MonoMethodSignature *tmp_sig;
1628 MonoInst *sig_arg;
1630 if (MONO_IS_TAILCALL_OPCODE (call))
1631 NOT_IMPLEMENTED;
1633 /* FIXME: Add support for signature tokens to AOT */
1634 cfg->disable_aot = TRUE;
1637 * mono_ArgIterator_Setup assumes the signature cookie is
1638 * passed first and all the arguments which were before it are
1639 * passed on the stack after the signature. So compensate by
1640 * passing a different signature.
1642 tmp_sig = mono_metadata_signature_dup (call->signature);
1643 tmp_sig->param_count -= call->signature->sentinelpos;
1644 tmp_sig->sentinelpos = 0;
1645 memcpy (tmp_sig->params, call->signature->params + call->signature->sentinelpos, tmp_sig->param_count * sizeof (MonoType*));
1647 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
1648 sig_arg->dreg = mono_alloc_ireg (cfg);
1649 sig_arg->inst_p0 = tmp_sig;
1650 MONO_ADD_INS (cfg->cbb, sig_arg);
1652 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_sp, cinfo->sig_cookie.offset, sig_arg->dreg);
1655 void
1656 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1658 MonoInst *in, *ins;
1659 MonoMethodSignature *sig;
1660 int i, n;
1661 CallInfo *cinfo;
1662 int is_virtual = 0;
1664 sig = call->signature;
1665 n = sig->param_count + sig->hasthis;
1667 cinfo = get_call_info (cfg->mempool, sig);
1668 if (cinfo->struct_ret)
1669 call->used_iregs |= 1 << cinfo->struct_ret;
1671 for (i = 0; i < n; ++i) {
1672 ArgInfo *ainfo = cinfo->args + i;
1673 MonoType *t;
1675 if (i >= sig->hasthis)
1676 t = sig->params [i - sig->hasthis];
1677 else
1678 t = mono_get_int_type ();
1679 t = mini_get_underlying_type (t);
1681 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1682 /* Emit the signature cookie just before the implicit arguments */
1683 emit_sig_cookie (cfg, call, cinfo);
1686 if (is_virtual && i == 0) {
1687 /* the argument will be attached to the call instrucion */
1688 in = call->args [i];
1689 call->used_iregs |= 1 << ainfo->reg;
1690 continue;
1692 in = call->args [i];
1693 if (ainfo->storage == ArgInIReg) {
1694 #if SIZEOF_REGISTER == 4
1695 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1696 MONO_INST_NEW (cfg, ins, OP_MOVE);
1697 ins->dreg = mono_alloc_ireg (cfg);
1698 ins->sreg1 = MONO_LVREG_LS (in->dreg);
1699 MONO_ADD_INS (cfg->cbb, ins);
1700 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + ls_word_idx, FALSE);
1702 MONO_INST_NEW (cfg, ins, OP_MOVE);
1703 ins->dreg = mono_alloc_ireg (cfg);
1704 ins->sreg1 = MONO_LVREG_MS (in->dreg);
1705 MONO_ADD_INS (cfg->cbb, ins);
1706 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + ms_word_idx, FALSE);
1707 } else
1708 #endif
1709 if (!t->byref && (t->type == MONO_TYPE_R4)) {
1710 int freg;
1712 #if PROMOTE_R4_TO_R8
1713 /* ??? - convert to single first? */
1714 MONO_INST_NEW (cfg, ins, OP_MIPS_CVTSD);
1715 ins->dreg = mono_alloc_freg (cfg);
1716 ins->sreg1 = in->dreg;
1717 MONO_ADD_INS (cfg->cbb, ins);
1718 freg = ins->dreg;
1719 #else
1720 freg = in->dreg;
1721 #endif
1722 /* trying to load float value into int registers */
1723 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1S);
1724 ins->dreg = mono_alloc_ireg (cfg);
1725 ins->sreg1 = freg;
1726 MONO_ADD_INS (cfg->cbb, ins);
1727 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1728 } else if (!t->byref && (t->type == MONO_TYPE_R8)) {
1729 /* trying to load float value into int registers */
1730 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1D);
1731 ins->dreg = mono_alloc_ireg (cfg);
1732 ins->sreg1 = in->dreg;
1733 MONO_ADD_INS (cfg->cbb, ins);
1734 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1735 } else {
1736 MONO_INST_NEW (cfg, ins, OP_MOVE);
1737 ins->dreg = mono_alloc_ireg (cfg);
1738 ins->sreg1 = in->dreg;
1739 MONO_ADD_INS (cfg->cbb, ins);
1740 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1742 } else if (ainfo->storage == ArgStructByAddr) {
1743 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1744 ins->opcode = OP_OUTARG_VT;
1745 ins->sreg1 = in->dreg;
1746 ins->klass = in->klass;
1747 ins->inst_p0 = call;
1748 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1749 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1750 MONO_ADD_INS (cfg->cbb, ins);
1751 } else if (ainfo->storage == ArgStructByVal) {
1752 /* this is further handled in mono_arch_emit_outarg_vt () */
1753 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1754 ins->opcode = OP_OUTARG_VT;
1755 ins->sreg1 = in->dreg;
1756 ins->klass = in->klass;
1757 ins->inst_p0 = call;
1758 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1759 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1760 MONO_ADD_INS (cfg->cbb, ins);
1761 } else if (ainfo->storage == ArgOnStack) {
1762 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1763 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1764 } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1765 if (t->type == MONO_TYPE_R8)
1766 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1767 else
1768 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1769 } else {
1770 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1772 } else if (ainfo->storage == ArgInFReg) {
1773 if (t->type == MONO_TYPE_VALUETYPE) {
1774 /* this is further handled in mono_arch_emit_outarg_vt () */
1775 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1776 ins->opcode = OP_OUTARG_VT;
1777 ins->sreg1 = in->dreg;
1778 ins->klass = in->klass;
1779 ins->inst_p0 = call;
1780 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1781 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1782 MONO_ADD_INS (cfg->cbb, ins);
1784 cfg->flags |= MONO_CFG_HAS_FPOUT;
1785 } else {
1786 int dreg = mono_alloc_freg (cfg);
1788 if (ainfo->size == 4) {
1789 MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, dreg, in->dreg);
1790 } else {
1791 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1792 ins->dreg = dreg;
1793 ins->sreg1 = in->dreg;
1794 MONO_ADD_INS (cfg->cbb, ins);
1797 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1798 cfg->flags |= MONO_CFG_HAS_FPOUT;
1800 } else {
1801 g_assert_not_reached ();
1805 /* Handle the case where there are no implicit arguments */
1806 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1807 emit_sig_cookie (cfg, call, cinfo);
1809 if (cinfo->struct_ret) {
1810 MonoInst *vtarg;
1812 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1813 vtarg->sreg1 = call->vret_var->dreg;
1814 vtarg->dreg = mono_alloc_preg (cfg);
1815 MONO_ADD_INS (cfg->cbb, vtarg);
1817 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1819 #if 0
1821 * Reverse the call->out_args list.
1824 MonoInst *prev = NULL, *list = call->out_args, *next;
1825 while (list) {
1826 next = list->next;
1827 list->next = prev;
1828 prev = list;
1829 list = next;
1831 call->out_args = prev;
1833 #endif
1834 call->stack_usage = cinfo->stack_usage;
1835 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1836 #if _MIPS_SIM == _ABIO32
1837 /* a0-a3 always present */
1838 cfg->param_area = MAX (cfg->param_area, 4 * SIZEOF_REGISTER);
1839 #endif
1840 cfg->param_area = (cfg->param_area + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1841 cfg->flags |= MONO_CFG_HAS_CALLS;
1843 * should set more info in call, such as the stack space
1844 * used by the args that needs to be added back to esp
1848 void
1849 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1851 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1852 ArgInfo *ainfo = ins->inst_p1;
1853 int ovf_size = ainfo->vtsize;
1854 int doffset = ainfo->offset;
1855 int i, soffset, dreg;
1857 if (ainfo->storage == ArgStructByVal) {
1858 #if 0
1859 if (cfg->verbose_level > 0) {
1860 char* nm = mono_method_full_name (cfg->method, TRUE);
1861 g_print ("Method %s outarg_vt struct doffset=%d ainfo->size=%d ovf_size=%d\n",
1862 nm, doffset, ainfo->size, ovf_size);
1863 g_free (nm);
1865 #endif
1867 soffset = 0;
1868 for (i = 0; i < ainfo->size; ++i) {
1869 dreg = mono_alloc_ireg (cfg);
1870 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1871 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1872 soffset += SIZEOF_REGISTER;
1874 if (ovf_size != 0) {
1875 mini_emit_memcpy (cfg, mips_sp, doffset, src->dreg, soffset, ovf_size * sizeof (target_mgreg_t), TARGET_SIZEOF_VOID_P);
1877 } else if (ainfo->storage == ArgInFReg) {
1878 int tmpr = mono_alloc_freg (cfg);
1880 if (ainfo->size == 4)
1881 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1882 else
1883 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1884 dreg = mono_alloc_freg (cfg);
1885 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1886 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1887 } else {
1888 MonoInst *vtcopy = mono_compile_create_var (cfg, m_class_get_byval_arg (src->klass), OP_LOCAL);
1889 MonoInst *load;
1890 guint32 size;
1892 /* FIXME: alignment? */
1893 if (call->signature->pinvoke) {
1894 size = mono_type_native_stack_size (m_class_get_byval_arg (src->klass), NULL);
1895 vtcopy->backend.is_pinvoke = 1;
1896 } else {
1897 size = mini_type_stack_size (m_class_get_byval_arg (src->klass), NULL);
1899 if (size > 0)
1900 g_assert (ovf_size > 0);
1902 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1903 mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, size, TARGET_SIZEOF_VOID_P);
1905 if (ainfo->offset)
1906 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_at, ainfo->offset, load->dreg);
1907 else
1908 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1912 void
1913 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1915 MonoType *ret = mini_get_underlying_type (mono_method_signature_internal (method)->ret);
1917 if (!ret->byref) {
1918 #if (SIZEOF_REGISTER == 4)
1919 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1920 MonoInst *ins;
1922 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1923 ins->sreg1 = MONO_LVREG_LS (val->dreg);
1924 ins->sreg2 = MONO_LVREG_MS (val->dreg);
1925 MONO_ADD_INS (cfg->cbb, ins);
1926 return;
1928 #endif
1929 if (ret->type == MONO_TYPE_R8) {
1930 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1931 return;
1933 if (ret->type == MONO_TYPE_R4) {
1934 MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, cfg->ret->dreg, val->dreg);
1935 return;
1938 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1941 void
1942 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1944 MonoInst *ins, *n, *last_ins = NULL;
1946 if (cfg->verbose_level > 2)
1947 g_print ("Basic block %d peephole pass 1\n", bb->block_num);
1949 ins = bb->code;
1950 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1951 if (cfg->verbose_level > 2)
1952 mono_print_ins_index (0, ins);
1954 switch (ins->opcode) {
1955 #if 0
1956 case OP_LOAD_MEMBASE:
1957 case OP_LOADI4_MEMBASE:
1959 * OP_IADD reg2, reg1, const1
1960 * OP_LOAD_MEMBASE const2(reg2), reg3
1961 * ->
1962 * OP_LOAD_MEMBASE (const1+const2)(reg1), reg3
1964 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)){
1965 int const1 = last_ins->inst_imm;
1966 int const2 = ins->inst_offset;
1968 if (mips_is_imm16 (const1 + const2)) {
1969 ins->inst_basereg = last_ins->sreg1;
1970 ins->inst_offset = const1 + const2;
1973 break;
1974 #endif
1977 last_ins = ins;
1978 ins = ins->next;
1980 bb->last_ins = last_ins;
1983 void
1984 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
1986 MonoInst *ins, *n, *last_ins = NULL;
1987 ins = bb->code;
1989 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1990 MonoInst *last_ins = ins->prev;
1992 switch (ins->opcode) {
1993 case OP_MUL_IMM:
1994 /* remove unnecessary multiplication with 1 */
1995 if (ins->inst_imm == 1) {
1996 if (ins->dreg != ins->sreg1) {
1997 ins->opcode = OP_MOVE;
1998 } else {
1999 MONO_DELETE_INS (bb, ins);
2000 continue;
2002 } else {
2003 int power2 = mono_is_power_of_two (ins->inst_imm);
2004 if (power2 > 0) {
2005 ins->opcode = OP_SHL_IMM;
2006 ins->inst_imm = power2;
2009 break;
2010 case OP_LOAD_MEMBASE:
2011 case OP_LOADI4_MEMBASE:
2013 * OP_STORE_MEMBASE_REG reg, offset(basereg)
2014 * OP_LOAD_MEMBASE offset(basereg), reg
2016 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
2017 || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
2018 ins->inst_basereg == last_ins->inst_destbasereg &&
2019 ins->inst_offset == last_ins->inst_offset) {
2020 if (ins->dreg == last_ins->sreg1) {
2021 MONO_DELETE_INS (bb, ins);
2022 continue;
2023 } else {
2024 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2025 ins->opcode = OP_MOVE;
2026 ins->sreg1 = last_ins->sreg1;
2028 break;
2031 * Note: reg1 must be different from the basereg in the second load
2032 * OP_LOAD_MEMBASE offset(basereg), reg1
2033 * OP_LOAD_MEMBASE offset(basereg), reg2
2034 * -->
2035 * OP_LOAD_MEMBASE offset(basereg), reg1
2036 * OP_MOVE reg1, reg2
2038 if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
2039 || last_ins->opcode == OP_LOAD_MEMBASE) &&
2040 ins->inst_basereg != last_ins->dreg &&
2041 ins->inst_basereg == last_ins->inst_basereg &&
2042 ins->inst_offset == last_ins->inst_offset) {
2044 if (ins->dreg == last_ins->dreg) {
2045 MONO_DELETE_INS (bb, ins);
2046 continue;
2047 } else {
2048 ins->opcode = OP_MOVE;
2049 ins->sreg1 = last_ins->dreg;
2052 //g_assert_not_reached ();
2053 break;
2055 #if 0
2057 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2058 * OP_LOAD_MEMBASE offset(basereg), reg
2059 * -->
2060 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2061 * OP_ICONST reg, imm
2063 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
2064 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
2065 ins->inst_basereg == last_ins->inst_destbasereg &&
2066 ins->inst_offset == last_ins->inst_offset) {
2067 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2068 ins->opcode = OP_ICONST;
2069 ins->inst_c0 = last_ins->inst_imm;
2070 g_assert_not_reached (); // check this rule
2071 break;
2073 #endif
2074 break;
2075 case OP_LOADU1_MEMBASE:
2076 case OP_LOADI1_MEMBASE:
2077 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
2078 ins->inst_basereg == last_ins->inst_destbasereg &&
2079 ins->inst_offset == last_ins->inst_offset) {
2080 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
2081 ins->sreg1 = last_ins->sreg1;
2083 break;
2084 case OP_LOADU2_MEMBASE:
2085 case OP_LOADI2_MEMBASE:
2086 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
2087 ins->inst_basereg == last_ins->inst_destbasereg &&
2088 ins->inst_offset == last_ins->inst_offset) {
2089 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
2090 ins->sreg1 = last_ins->sreg1;
2092 break;
2093 case OP_ICONV_TO_I4:
2094 case OP_ICONV_TO_U4:
2095 case OP_MOVE:
2096 ins->opcode = OP_MOVE;
2098 * OP_MOVE reg, reg
2100 if (ins->dreg == ins->sreg1) {
2101 MONO_DELETE_INS (bb, ins);
2102 continue;
2105 * OP_MOVE sreg, dreg
2106 * OP_MOVE dreg, sreg
2108 if (last_ins && last_ins->opcode == OP_MOVE &&
2109 ins->sreg1 == last_ins->dreg &&
2110 ins->dreg == last_ins->sreg1) {
2111 MONO_DELETE_INS (bb, ins);
2112 continue;
2114 break;
2116 last_ins = ins;
2117 ins = ins->next;
2119 bb->last_ins = last_ins;
2122 void
2123 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins)
2125 int tmp1 = -1;
2126 int tmp2 = -1;
2127 int tmp3 = -1;
2128 int tmp4 = -1;
2129 int tmp5 = -1;
2131 switch (ins->opcode) {
2132 case OP_LADD:
2133 tmp1 = mono_alloc_ireg (cfg);
2134 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2135 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2136 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2137 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
2138 NULLIFY_INS(ins);
2139 break;
2141 case OP_LADD_IMM:
2142 tmp1 = mono_alloc_ireg (cfg);
2143 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+1, ins->sreg1+1, ins_get_l_low (ins));
2144 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2145 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+2, ins->sreg1+2, ins_get_l_high (ins));
2146 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
2147 NULLIFY_INS(ins);
2148 break;
2150 case OP_LSUB:
2151 tmp1 = mono_alloc_ireg (cfg);
2152 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2153 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2154 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2155 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2156 NULLIFY_INS(ins);
2157 break;
2159 case OP_LSUB_IMM:
2160 tmp1 = mono_alloc_ireg (cfg);
2161 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+1, ins->sreg1+1, ins_get_l_low (ins));
2162 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2163 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+2, ins->sreg1+2, ins_get_l_high (ins));
2164 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2165 NULLIFY_INS(ins);
2166 break;
2168 case OP_LNEG:
2169 tmp1 = mono_alloc_ireg (cfg);
2170 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, mips_zero, ins->sreg1+1);
2171 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, mips_zero, ins->dreg+1);
2172 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, mips_zero, ins->sreg1+2);
2173 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2174 NULLIFY_INS(ins);
2175 break;
2177 case OP_LADD_OVF:
2178 tmp1 = mono_alloc_ireg (cfg);
2179 tmp2 = mono_alloc_ireg (cfg);
2180 tmp3 = mono_alloc_ireg (cfg);
2181 tmp4 = mono_alloc_ireg (cfg);
2182 tmp5 = mono_alloc_ireg (cfg);
2184 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2186 /* tmp1 holds the carry from the low 32-bit to the high 32-bits */
2187 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->dreg+1, ins->sreg1+1);
2189 /* add the high 32-bits, and add in the carry from the low 32-bits */
2190 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2191 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp5, ins->dreg+2);
2193 /* Overflow happens if
2194 * neg + neg = pos or
2195 * pos + pos = neg
2196 * XOR of the high bits returns 0 if the signs match
2197 * XOR of that with the high bit of the result return 1 if overflow.
2200 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2201 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2203 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2204 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg+2, ins->sreg2+2);
2205 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp2, tmp2);
2207 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2208 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp3, tmp2, tmp1);
2209 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2211 /* Now, if (tmp4 == 0) then overflow */
2212 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp4, mips_zero, "OverflowException");
2213 NULLIFY_INS(ins);
2214 break;
2216 case OP_LADD_OVF_UN:
2217 tmp1 = mono_alloc_ireg (cfg);
2218 tmp2 = mono_alloc_ireg (cfg);
2220 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2221 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2222 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2223 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp1, ins->dreg+2);
2224 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->dreg+2, ins->sreg1+2);
2225 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2226 NULLIFY_INS(ins);
2227 break;
2229 case OP_LSUB_OVF:
2230 tmp1 = mono_alloc_ireg (cfg);
2231 tmp2 = mono_alloc_ireg (cfg);
2232 tmp3 = mono_alloc_ireg (cfg);
2233 tmp4 = mono_alloc_ireg (cfg);
2234 tmp5 = mono_alloc_ireg (cfg);
2236 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2238 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->sreg1+1, ins->dreg+1);
2239 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2240 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp5);
2242 /* Overflow happens if
2243 * neg - pos = pos or
2244 * pos - neg = neg
2245 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2247 * tmp1 = (lhs ^ rhs)
2248 * tmp2 = (lhs ^ result)
2249 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2252 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2253 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1+2, ins->dreg+2);
2254 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp3, tmp2, tmp1);
2255 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2257 /* Now, if (tmp4 == 1) then overflow */
2258 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp4, mips_zero, "OverflowException");
2259 NULLIFY_INS(ins);
2260 break;
2262 case OP_LSUB_OVF_UN:
2263 tmp1 = mono_alloc_ireg (cfg);
2264 tmp2 = mono_alloc_ireg (cfg);
2266 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2267 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2268 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2269 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2271 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->sreg1+2, ins->dreg+2);
2272 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2273 NULLIFY_INS(ins);
2274 break;
2275 case OP_LCONV_TO_OVF_I4_2:
2276 tmp1 = mono_alloc_ireg (cfg);
2278 /* Overflows if reg2 != sign extension of reg1 */
2279 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp1, ins->sreg1, 31);
2280 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, ins->sreg2, tmp1, "OverflowException");
2281 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
2282 NULLIFY_INS(ins);
2283 break;
2284 default:
2285 break;
2289 void
2290 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
2292 int tmp1 = -1;
2293 int tmp2 = -1;
2294 int tmp3 = -1;
2295 int tmp4 = -1;
2296 int tmp5 = -1;
2298 switch (ins->opcode) {
2299 case OP_IADD_OVF:
2300 tmp1 = mono_alloc_ireg (cfg);
2301 tmp2 = mono_alloc_ireg (cfg);
2302 tmp3 = mono_alloc_ireg (cfg);
2303 tmp4 = mono_alloc_ireg (cfg);
2304 tmp5 = mono_alloc_ireg (cfg);
2306 /* add the operands */
2308 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2310 /* Overflow happens if
2311 * neg + neg = pos or
2312 * pos + pos = neg
2314 * (bit31s of operands match) AND (bit31 of operand != bit31 of result)
2315 * XOR of the high bit returns 0 if the signs match
2316 * XOR of that with the high bit of the result return 1 if overflow.
2319 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2320 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2322 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2323 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg, ins->sreg2);
2324 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp3, tmp2);
2326 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2327 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp4, tmp3, tmp1);
2329 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp5, tmp4, 31);
2331 /* Now, if (tmp5 == 0) then overflow */
2332 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp5, mips_zero, "OverflowException");
2333 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2334 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2335 NULLIFY_INS(ins);
2336 break;
2338 case OP_IADD_OVF_UN:
2339 tmp1 = mono_alloc_ireg (cfg);
2341 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2342 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg, ins->sreg1);
2343 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2344 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2345 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2346 NULLIFY_INS(ins);
2347 break;
2349 case OP_ISUB_OVF:
2350 tmp1 = mono_alloc_ireg (cfg);
2351 tmp2 = mono_alloc_ireg (cfg);
2352 tmp3 = mono_alloc_ireg (cfg);
2353 tmp4 = mono_alloc_ireg (cfg);
2354 tmp5 = mono_alloc_ireg (cfg);
2356 /* add the operands */
2358 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2360 /* Overflow happens if
2361 * neg - pos = pos or
2362 * pos - neg = neg
2363 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2365 * tmp1 = (lhs ^ rhs)
2366 * tmp2 = (lhs ^ result)
2367 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2370 /* tmp3 = 1 if the signs of the two inputs differ */
2371 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2372 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1, ins->dreg);
2373 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp3, tmp1, 0);
2374 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp4, tmp2, 0);
2375 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp5, tmp4, tmp3);
2377 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp5, mips_zero, "OverflowException");
2378 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2379 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2380 NULLIFY_INS(ins);
2381 break;
2383 case OP_ISUB_OVF_UN:
2384 tmp1 = mono_alloc_ireg (cfg);
2386 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2387 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1, ins->dreg);
2388 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2389 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2390 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2391 NULLIFY_INS(ins);
2392 break;
2396 static int
2397 map_to_reg_reg_op (int op)
2399 switch (op) {
2400 case OP_ADD_IMM:
2401 return OP_IADD;
2402 case OP_SUB_IMM:
2403 return OP_ISUB;
2404 case OP_AND_IMM:
2405 return OP_IAND;
2406 case OP_COMPARE_IMM:
2407 return OP_COMPARE;
2408 case OP_ICOMPARE_IMM:
2409 return OP_ICOMPARE;
2410 case OP_LCOMPARE_IMM:
2411 return OP_LCOMPARE;
2412 case OP_ADDCC_IMM:
2413 return OP_IADDCC;
2414 case OP_ADC_IMM:
2415 return OP_IADC;
2416 case OP_SUBCC_IMM:
2417 return OP_ISUBCC;
2418 case OP_SBB_IMM:
2419 return OP_ISBB;
2420 case OP_OR_IMM:
2421 return OP_IOR;
2422 case OP_XOR_IMM:
2423 return OP_IXOR;
2424 case OP_MUL_IMM:
2425 return OP_IMUL;
2426 case OP_LOAD_MEMBASE:
2427 return OP_LOAD_MEMINDEX;
2428 case OP_LOADI4_MEMBASE:
2429 return OP_LOADI4_MEMINDEX;
2430 case OP_LOADU4_MEMBASE:
2431 return OP_LOADU4_MEMINDEX;
2432 case OP_LOADU1_MEMBASE:
2433 return OP_LOADU1_MEMINDEX;
2434 case OP_LOADI2_MEMBASE:
2435 return OP_LOADI2_MEMINDEX;
2436 case OP_LOADU2_MEMBASE:
2437 return OP_LOADU2_MEMINDEX;
2438 case OP_LOADI1_MEMBASE:
2439 return OP_LOADI1_MEMINDEX;
2440 case OP_LOADR4_MEMBASE:
2441 return OP_LOADR4_MEMINDEX;
2442 case OP_LOADR8_MEMBASE:
2443 return OP_LOADR8_MEMINDEX;
2444 case OP_STOREI1_MEMBASE_REG:
2445 return OP_STOREI1_MEMINDEX;
2446 case OP_STOREI2_MEMBASE_REG:
2447 return OP_STOREI2_MEMINDEX;
2448 case OP_STOREI4_MEMBASE_REG:
2449 return OP_STOREI4_MEMINDEX;
2450 case OP_STORE_MEMBASE_REG:
2451 return OP_STORE_MEMINDEX;
2452 case OP_STORER4_MEMBASE_REG:
2453 return OP_STORER4_MEMINDEX;
2454 case OP_STORER8_MEMBASE_REG:
2455 return OP_STORER8_MEMINDEX;
2456 case OP_STORE_MEMBASE_IMM:
2457 return OP_STORE_MEMBASE_REG;
2458 case OP_STOREI1_MEMBASE_IMM:
2459 return OP_STOREI1_MEMBASE_REG;
2460 case OP_STOREI2_MEMBASE_IMM:
2461 return OP_STOREI2_MEMBASE_REG;
2462 case OP_STOREI4_MEMBASE_IMM:
2463 return OP_STOREI4_MEMBASE_REG;
2464 case OP_STOREI8_MEMBASE_IMM:
2465 return OP_STOREI8_MEMBASE_REG;
2467 if (mono_op_imm_to_op (op) == -1)
2468 g_error ("mono_op_imm_to_op failed for %s\n", mono_inst_name (op));
2469 return mono_op_imm_to_op (op);
2472 static int
2473 map_to_mips_op (int op)
2475 switch (op) {
2476 case OP_FBEQ:
2477 return OP_MIPS_FBEQ;
2478 case OP_FBGE:
2479 return OP_MIPS_FBGE;
2480 case OP_FBGT:
2481 return OP_MIPS_FBGT;
2482 case OP_FBLE:
2483 return OP_MIPS_FBLE;
2484 case OP_FBLT:
2485 return OP_MIPS_FBLT;
2486 case OP_FBNE_UN:
2487 return OP_MIPS_FBNE;
2488 case OP_FBGE_UN:
2489 return OP_MIPS_FBGE_UN;
2490 case OP_FBGT_UN:
2491 return OP_MIPS_FBGT_UN;
2492 case OP_FBLE_UN:
2493 return OP_MIPS_FBLE_UN;
2494 case OP_FBLT_UN:
2495 return OP_MIPS_FBLT_UN;
2497 case OP_FCEQ:
2498 case OP_FCGT:
2499 case OP_FCGT_UN:
2500 case OP_FCLT:
2501 case OP_FCLT_UN:
2502 default:
2503 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (op), __FUNCTION__);
2504 g_assert_not_reached ();
2508 #define NEW_INS(cfg,after,dest,op) do { \
2509 MONO_INST_NEW((cfg), (dest), (op)); \
2510 mono_bblock_insert_after_ins (bb, (after), (dest)); \
2511 } while (0)
2513 #define INS(pos,op,_dreg,_sreg1,_sreg2) do { \
2514 MonoInst *temp; \
2515 MONO_INST_NEW(cfg, temp, (op)); \
2516 mono_bblock_insert_after_ins (bb, (pos), temp); \
2517 temp->dreg = (_dreg); \
2518 temp->sreg1 = (_sreg1); \
2519 temp->sreg2 = (_sreg2); \
2520 pos = temp; \
2521 } while (0)
2523 #define INS_IMM(pos,op,_dreg,_sreg1,_imm) do { \
2524 MonoInst *temp; \
2525 MONO_INST_NEW(cfg, temp, (op)); \
2526 mono_bblock_insert_after_ins (bb, (pos), temp); \
2527 temp->dreg = (_dreg); \
2528 temp->sreg1 = (_sreg1); \
2529 temp->inst_c0 = (_imm); \
2530 pos = temp; \
2531 } while (0)
2534 * Remove from the instruction list the instructions that can't be
2535 * represented with very simple instructions with no register
2536 * requirements.
2538 void
2539 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2541 MonoInst *ins, *next, *temp, *last_ins = NULL;
2542 int imm;
2544 #if 1
2545 if (cfg->verbose_level > 2) {
2546 int idx = 0;
2548 g_print ("BASIC BLOCK %d (before lowering)\n", bb->block_num);
2549 MONO_BB_FOR_EACH_INS (bb, ins) {
2550 mono_print_ins_index (idx++, ins);
2554 #endif
2556 MONO_BB_FOR_EACH_INS (bb, ins) {
2557 loop_start:
2558 switch (ins->opcode) {
2559 case OP_COMPARE:
2560 case OP_ICOMPARE:
2561 case OP_LCOMPARE:
2562 next = ins->next;
2563 /* Branch opts can eliminate the branch */
2564 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2565 NULLIFY_INS(ins);
2566 break;
2568 break;
2570 case OP_COMPARE_IMM:
2571 case OP_ICOMPARE_IMM:
2572 case OP_LCOMPARE_IMM:
2573 next = ins->next;
2574 /* Branch opts can eliminate the branch */
2575 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2576 NULLIFY_INS(ins);
2577 break;
2579 if (ins->inst_imm) {
2580 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2581 temp->inst_c0 = ins->inst_imm;
2582 temp->dreg = mono_alloc_ireg (cfg);
2583 ins->sreg2 = temp->dreg;
2584 last_ins = temp;
2586 else {
2587 ins->sreg2 = mips_zero;
2589 if (ins->opcode == OP_COMPARE_IMM)
2590 ins->opcode = OP_COMPARE;
2591 else if (ins->opcode == OP_ICOMPARE_IMM)
2592 ins->opcode = OP_ICOMPARE;
2593 else if (ins->opcode == OP_LCOMPARE_IMM)
2594 ins->opcode = OP_LCOMPARE;
2595 goto loop_start;
2597 case OP_IDIV_UN_IMM:
2598 case OP_IDIV_IMM:
2599 case OP_IREM_IMM:
2600 case OP_IREM_UN_IMM:
2601 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2602 temp->inst_c0 = ins->inst_imm;
2603 temp->dreg = mono_alloc_ireg (cfg);
2604 ins->sreg2 = temp->dreg;
2605 if (ins->opcode == OP_IDIV_IMM)
2606 ins->opcode = OP_IDIV;
2607 else if (ins->opcode == OP_IREM_IMM)
2608 ins->opcode = OP_IREM;
2609 else if (ins->opcode == OP_IDIV_UN_IMM)
2610 ins->opcode = OP_IDIV_UN;
2611 else if (ins->opcode == OP_IREM_UN_IMM)
2612 ins->opcode = OP_IREM_UN;
2613 last_ins = temp;
2614 /* handle rem separately */
2615 goto loop_start;
2617 #if 0
2618 case OP_AND_IMM:
2619 case OP_OR_IMM:
2620 case OP_XOR_IMM:
2621 if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
2622 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2623 temp->inst_c0 = ins->inst_imm;
2624 temp->dreg = mono_alloc_ireg (cfg);
2625 ins->sreg2 = temp->dreg;
2626 ins->opcode = map_to_reg_reg_op (ins->opcode);
2628 break;
2629 #endif
2630 case OP_AND_IMM:
2631 case OP_IAND_IMM:
2632 case OP_OR_IMM:
2633 case OP_IOR_IMM:
2634 case OP_XOR_IMM:
2635 case OP_IXOR_IMM:
2636 /* unsigned 16 bit immediate */
2637 if (ins->inst_imm & 0xffff0000) {
2638 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2639 temp->inst_c0 = ins->inst_imm;
2640 temp->dreg = mono_alloc_ireg (cfg);
2641 ins->sreg2 = temp->dreg;
2642 ins->opcode = map_to_reg_reg_op (ins->opcode);
2644 break;
2646 case OP_IADD_IMM:
2647 case OP_ADD_IMM:
2648 case OP_ADDCC_IMM:
2649 /* signed 16 bit immediate */
2650 if (!mips_is_imm16 (ins->inst_imm)) {
2651 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2652 temp->inst_c0 = ins->inst_imm;
2653 temp->dreg = mono_alloc_ireg (cfg);
2654 ins->sreg2 = temp->dreg;
2655 ins->opcode = map_to_reg_reg_op (ins->opcode);
2657 break;
2659 case OP_SUB_IMM:
2660 case OP_ISUB_IMM:
2661 if (!mips_is_imm16 (-ins->inst_imm)) {
2662 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2663 temp->inst_c0 = ins->inst_imm;
2664 temp->dreg = mono_alloc_ireg (cfg);
2665 ins->sreg2 = temp->dreg;
2666 ins->opcode = map_to_reg_reg_op (ins->opcode);
2668 break;
2670 case OP_MUL_IMM:
2671 case OP_IMUL_IMM:
2672 if (ins->inst_imm == 1) {
2673 ins->opcode = OP_MOVE;
2674 break;
2676 if (ins->inst_imm == 0) {
2677 ins->opcode = OP_ICONST;
2678 ins->inst_c0 = 0;
2679 break;
2681 imm = mono_is_power_of_two (ins->inst_imm);
2682 if (imm > 0) {
2683 ins->opcode = OP_SHL_IMM;
2684 ins->inst_imm = imm;
2685 break;
2687 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2688 temp->inst_c0 = ins->inst_imm;
2689 temp->dreg = mono_alloc_ireg (cfg);
2690 ins->sreg2 = temp->dreg;
2691 ins->opcode = map_to_reg_reg_op (ins->opcode);
2692 break;
2694 case OP_LOCALLOC_IMM:
2695 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2696 temp->inst_c0 = ins->inst_imm;
2697 temp->dreg = mono_alloc_ireg (cfg);
2698 ins->sreg1 = temp->dreg;
2699 ins->opcode = OP_LOCALLOC;
2700 break;
2702 case OP_LOADR4_MEMBASE:
2703 case OP_STORER4_MEMBASE_REG:
2704 /* we can do two things: load the immed in a register
2705 * and use an indexed load, or see if the immed can be
2706 * represented as an ad_imm + a load with a smaller offset
2707 * that fits. We just do the first for now, optimize later.
2709 if (mips_is_imm16 (ins->inst_offset))
2710 break;
2711 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2712 temp->inst_c0 = ins->inst_offset;
2713 temp->dreg = mono_alloc_ireg (cfg);
2714 ins->sreg2 = temp->dreg;
2715 ins->opcode = map_to_reg_reg_op (ins->opcode);
2716 break;
2718 case OP_STORE_MEMBASE_IMM:
2719 case OP_STOREI1_MEMBASE_IMM:
2720 case OP_STOREI2_MEMBASE_IMM:
2721 case OP_STOREI4_MEMBASE_IMM:
2722 case OP_STOREI8_MEMBASE_IMM:
2723 if (!ins->inst_imm) {
2724 ins->sreg1 = mips_zero;
2725 ins->opcode = map_to_reg_reg_op (ins->opcode);
2727 else {
2728 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2729 temp->inst_c0 = ins->inst_imm;
2730 temp->dreg = mono_alloc_ireg (cfg);
2731 ins->sreg1 = temp->dreg;
2732 ins->opcode = map_to_reg_reg_op (ins->opcode);
2733 last_ins = temp;
2734 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2736 break;
2738 case OP_FCOMPARE:
2739 next = ins->next;
2740 /* Branch opts can eliminate the branch */
2741 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2742 NULLIFY_INS(ins);
2743 break;
2745 g_assert(next);
2748 * remap compare/branch and compare/set
2749 * to MIPS specific opcodes.
2751 next->opcode = map_to_mips_op (next->opcode);
2752 next->sreg1 = ins->sreg1;
2753 next->sreg2 = ins->sreg2;
2754 NULLIFY_INS(ins);
2755 break;
2757 #if 0
2758 case OP_R8CONST:
2759 case OP_R4CONST:
2760 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2761 temp->inst_c0 = (guint32)ins->inst_p0;
2762 temp->dreg = mono_alloc_ireg (cfg);
2763 ins->inst_basereg = temp->dreg;
2764 ins->inst_offset = 0;
2765 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2766 last_ins = temp;
2767 /* make it handle the possibly big ins->inst_offset
2768 * later optimize to use lis + load_membase
2770 goto loop_start;
2771 #endif
2772 case OP_IBEQ:
2773 g_assert (ins_is_compare(last_ins));
2774 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->sreg1, last_ins->sreg2);
2775 NULLIFY_INS(last_ins);
2776 break;
2778 case OP_IBNE_UN:
2779 g_assert (ins_is_compare(last_ins));
2780 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->sreg1, last_ins->sreg2);
2781 NULLIFY_INS(last_ins);
2782 break;
2784 case OP_IBGE:
2785 g_assert (ins_is_compare(last_ins));
2786 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2787 last_ins->dreg = mono_alloc_ireg (cfg);
2788 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2789 break;
2791 case OP_IBGE_UN:
2792 g_assert (ins_is_compare(last_ins));
2793 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2794 last_ins->dreg = mono_alloc_ireg (cfg);
2795 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2796 break;
2798 case OP_IBLT:
2799 g_assert (ins_is_compare(last_ins));
2800 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2801 last_ins->dreg = mono_alloc_ireg (cfg);
2802 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2803 break;
2805 case OP_IBLT_UN:
2806 g_assert (ins_is_compare(last_ins));
2807 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2808 last_ins->dreg = mono_alloc_ireg (cfg);
2809 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2810 break;
2812 case OP_IBLE:
2813 g_assert (ins_is_compare(last_ins));
2814 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2815 last_ins->dreg = mono_alloc_ireg (cfg);
2816 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2817 break;
2819 case OP_IBLE_UN:
2820 g_assert (ins_is_compare(last_ins));
2821 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2822 last_ins->dreg = mono_alloc_ireg (cfg);
2823 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2824 break;
2826 case OP_IBGT:
2827 g_assert (ins_is_compare(last_ins));
2828 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2829 last_ins->dreg = mono_alloc_ireg (cfg);
2830 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2831 break;
2833 case OP_IBGT_UN:
2834 g_assert (ins_is_compare(last_ins));
2835 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2836 last_ins->dreg = mono_alloc_ireg (cfg);
2837 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2838 break;
2840 case OP_CEQ:
2841 case OP_ICEQ:
2842 g_assert (ins_is_compare(last_ins));
2843 last_ins->opcode = OP_IXOR;
2844 last_ins->dreg = mono_alloc_ireg(cfg);
2845 INS_REWRITE_IMM(ins, OP_MIPS_SLTIU, last_ins->dreg, 1);
2846 break;
2848 case OP_CLT:
2849 case OP_ICLT:
2850 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2851 NULLIFY_INS(last_ins);
2852 break;
2855 case OP_CLT_UN:
2856 case OP_ICLT_UN:
2857 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2858 NULLIFY_INS(last_ins);
2859 break;
2861 case OP_CGT:
2862 case OP_ICGT:
2863 g_assert (ins_is_compare(last_ins));
2864 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2865 MONO_DELETE_INS(bb, last_ins);
2866 break;
2868 case OP_CGT_UN:
2869 case OP_ICGT_UN:
2870 g_assert (ins_is_compare(last_ins));
2871 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2872 MONO_DELETE_INS(bb, last_ins);
2873 break;
2875 case OP_COND_EXC_EQ:
2876 case OP_COND_EXC_IEQ:
2877 g_assert (ins_is_compare(last_ins));
2878 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, last_ins->sreg1, last_ins->sreg2);
2879 MONO_DELETE_INS(bb, last_ins);
2880 break;
2882 case OP_COND_EXC_GE:
2883 case OP_COND_EXC_IGE:
2884 g_assert (ins_is_compare(last_ins));
2885 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE, last_ins->sreg1, last_ins->sreg2);
2886 MONO_DELETE_INS(bb, last_ins);
2887 break;
2889 case OP_COND_EXC_GT:
2890 case OP_COND_EXC_IGT:
2891 g_assert (ins_is_compare(last_ins));
2892 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT, last_ins->sreg1, last_ins->sreg2);
2893 MONO_DELETE_INS(bb, last_ins);
2894 break;
2896 case OP_COND_EXC_LE:
2897 case OP_COND_EXC_ILE:
2898 g_assert (ins_is_compare(last_ins));
2899 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE, last_ins->sreg1, last_ins->sreg2);
2900 MONO_DELETE_INS(bb, last_ins);
2901 break;
2903 case OP_COND_EXC_LT:
2904 case OP_COND_EXC_ILT:
2905 g_assert (ins_is_compare(last_ins));
2906 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT, last_ins->sreg1, last_ins->sreg2);
2907 MONO_DELETE_INS(bb, last_ins);
2908 break;
2910 case OP_COND_EXC_NE_UN:
2911 case OP_COND_EXC_INE_UN:
2912 g_assert (ins_is_compare(last_ins));
2913 INS_REWRITE(ins, OP_MIPS_COND_EXC_NE_UN, last_ins->sreg1, last_ins->sreg2);
2914 MONO_DELETE_INS(bb, last_ins);
2915 break;
2917 case OP_COND_EXC_GE_UN:
2918 case OP_COND_EXC_IGE_UN:
2919 g_assert (ins_is_compare(last_ins));
2920 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE_UN, last_ins->sreg1, last_ins->sreg2);
2921 MONO_DELETE_INS(bb, last_ins);
2922 break;
2924 case OP_COND_EXC_GT_UN:
2925 case OP_COND_EXC_IGT_UN:
2926 g_assert (ins_is_compare(last_ins));
2927 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT_UN, last_ins->sreg1, last_ins->sreg2);
2928 MONO_DELETE_INS(bb, last_ins);
2929 break;
2931 case OP_COND_EXC_LE_UN:
2932 case OP_COND_EXC_ILE_UN:
2933 g_assert (ins_is_compare(last_ins));
2934 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE_UN, last_ins->sreg1, last_ins->sreg2);
2935 MONO_DELETE_INS(bb, last_ins);
2936 break;
2938 case OP_COND_EXC_LT_UN:
2939 case OP_COND_EXC_ILT_UN:
2940 g_assert (ins_is_compare(last_ins));
2941 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT_UN, last_ins->sreg1, last_ins->sreg2);
2942 MONO_DELETE_INS(bb, last_ins);
2943 break;
2945 case OP_COND_EXC_OV:
2946 case OP_COND_EXC_IOV: {
2947 int tmp1, tmp2, tmp3, tmp4, tmp5;
2948 MonoInst *pos = last_ins;
2950 /* Overflow happens if
2951 * neg + neg = pos or
2952 * pos + pos = neg
2954 * (bit31s of operands match) AND (bit31 of operand
2955 * != bit31 of result)
2956 * XOR of the high bit returns 0 if the signs match
2957 * XOR of that with the high bit of the result return 1
2958 * if overflow.
2960 g_assert (last_ins->opcode == OP_IADC);
2962 tmp1 = mono_alloc_ireg (cfg);
2963 tmp2 = mono_alloc_ireg (cfg);
2964 tmp3 = mono_alloc_ireg (cfg);
2965 tmp4 = mono_alloc_ireg (cfg);
2966 tmp5 = mono_alloc_ireg (cfg);
2968 /* tmp1 = 0 if the signs of the two inputs match, else 1 */
2969 INS (pos, OP_IXOR, tmp1, last_ins->sreg1, last_ins->sreg2);
2971 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2972 INS (pos, OP_IXOR, tmp2, last_ins->dreg, last_ins->sreg2);
2973 INS (pos, OP_INOT, tmp3, tmp2, -1);
2975 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2976 INS (pos, OP_IOR, tmp4, tmp3, tmp1);
2977 INS_IMM (pos, OP_SHR_IMM, tmp5, tmp4, 31);
2979 /* Now, if (tmp5 == 0) then overflow */
2980 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, tmp5, mips_zero);
2981 ins->dreg = -1;
2982 break;
2985 case OP_COND_EXC_NO:
2986 case OP_COND_EXC_INO:
2987 g_assert_not_reached ();
2988 break;
2990 case OP_COND_EXC_C:
2991 case OP_COND_EXC_IC:
2992 g_assert_not_reached ();
2993 break;
2995 case OP_COND_EXC_NC:
2996 case OP_COND_EXC_INC:
2997 g_assert_not_reached ();
2998 break;
3001 last_ins = ins;
3003 bb->last_ins = last_ins;
3004 bb->max_vreg = cfg->next_vreg;
3006 #if 1
3007 if (cfg->verbose_level > 2) {
3008 int idx = 0;
3010 g_print ("BASIC BLOCK %d (after lowering)\n", bb->block_num);
3011 MONO_BB_FOR_EACH_INS (bb, ins) {
3012 mono_print_ins_index (idx++, ins);
3016 #endif
3020 static guchar*
3021 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
3023 /* sreg is a float, dreg is an integer reg. mips_at is used as scratch */
3024 #if 1
3025 mips_truncwd (code, mips_ftemp, sreg);
3026 #else
3027 mips_cvtwd (code, mips_ftemp, sreg);
3028 #endif
3029 mips_mfc1 (code, dreg, mips_ftemp);
3030 if (!is_signed) {
3031 if (size == 1)
3032 mips_andi (code, dreg, dreg, 0xff);
3033 else if (size == 2) {
3034 mips_sll (code, dreg, dreg, 16);
3035 mips_srl (code, dreg, dreg, 16);
3037 } else {
3038 if (size == 1) {
3039 mips_sll (code, dreg, dreg, 24);
3040 mips_sra (code, dreg, dreg, 24);
3042 else if (size == 2) {
3043 mips_sll (code, dreg, dreg, 16);
3044 mips_sra (code, dreg, dreg, 16);
3047 return code;
3051 * emit_load_volatile_arguments:
3053 * Load volatile arguments from the stack to the original input registers.
3054 * Required before a tailcall.
3056 static guint8 *
3057 emit_load_volatile_arguments(MonoCompile *cfg, guint8 *code)
3059 MonoMethod *method = cfg->method;
3060 MonoMethodSignature *sig;
3061 MonoInst *inst;
3062 CallInfo *cinfo;
3063 int i;
3065 sig = mono_method_signature_internal (method);
3067 if (!cfg->arch.cinfo)
3068 cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
3069 cinfo = cfg->arch.cinfo;
3071 if (cinfo->struct_ret) {
3072 ArgInfo *ainfo = &cinfo->ret;
3073 inst = cfg->vret_addr;
3074 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3077 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3078 ArgInfo *ainfo = cinfo->args + i;
3079 inst = cfg->args [i];
3080 if (inst->opcode == OP_REGVAR) {
3081 if (ainfo->storage == ArgInIReg)
3082 MIPS_MOVE (code, ainfo->reg, inst->dreg);
3083 else if (ainfo->storage == ArgInFReg)
3084 g_assert_not_reached();
3085 else if (ainfo->storage == ArgOnStack) {
3086 /* do nothing */
3087 } else
3088 g_assert_not_reached ();
3089 } else {
3090 if (ainfo->storage == ArgInIReg) {
3091 g_assert (mips_is_imm16 (inst->inst_offset));
3092 switch (ainfo->size) {
3093 case 1:
3094 mips_lb (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3095 break;
3096 case 2:
3097 mips_lh (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3098 break;
3099 case 0: /* XXX */
3100 case 4:
3101 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3102 break;
3103 case 8:
3104 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
3105 mips_lw (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
3106 break;
3107 default:
3108 g_assert_not_reached ();
3109 break;
3111 } else if (ainfo->storage == ArgOnStack) {
3112 /* do nothing */
3113 } else if (ainfo->storage == ArgInFReg) {
3114 g_assert (mips_is_imm16 (inst->inst_offset));
3115 if (ainfo->size == 8) {
3116 #if _MIPS_SIM == _ABIO32
3117 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
3118 mips_lwc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
3119 #elif _MIPS_SIM == _ABIN32
3120 mips_ldc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3121 #endif
3123 else if (ainfo->size == 4)
3124 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3125 else
3126 g_assert_not_reached ();
3127 } else if (ainfo->storage == ArgStructByVal) {
3128 int i;
3129 int doffset = inst->inst_offset;
3131 g_assert (mips_is_imm16 (inst->inst_offset));
3132 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (target_mgreg_t)));
3133 for (i = 0; i < ainfo->size; ++i) {
3134 mips_lw (code, ainfo->reg + i, inst->inst_basereg, doffset);
3135 doffset += SIZEOF_REGISTER;
3137 } else if (ainfo->storage == ArgStructByAddr) {
3138 g_assert (mips_is_imm16 (inst->inst_offset));
3139 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3140 } else
3141 g_assert_not_reached ();
3145 return code;
3148 static guint8*
3149 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
3151 int size = cfg->param_area;
3153 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3154 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3156 if (!size)
3157 return code;
3158 #if 0
3159 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3160 if (ppc_is_imm16 (-size)) {
3161 ppc_stwu (code, ppc_r0, -size, ppc_sp);
3162 } else {
3163 ppc_load (code, ppc_r12, -size);
3164 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r12);
3166 #endif
3167 return code;
3170 static guint8*
3171 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
3173 int size = cfg->param_area;
3175 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3176 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3178 if (!size)
3179 return code;
3180 #if 0
3181 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3182 if (ppc_is_imm16 (size)) {
3183 ppc_stwu (code, ppc_r0, size, ppc_sp);
3184 } else {
3185 ppc_load (code, ppc_r12, size);
3186 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r12);
3188 #endif
3189 return code;
3192 void
3193 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3195 MonoInst *ins;
3196 MonoCallInst *call;
3197 guint8 *code = cfg->native_code + cfg->code_len;
3198 MonoInst *last_ins = NULL;
3199 int max_len, cpos;
3200 int ins_cnt = 0;
3202 /* we don't align basic blocks of loops on mips */
3204 if (cfg->verbose_level > 2)
3205 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3207 cpos = bb->max_offset;
3209 MONO_BB_FOR_EACH_INS (bb, ins) {
3210 const guint offset = code - cfg->native_code;
3211 set_code_cursor (cfg, code);
3212 max_len = ins_get_size (ins->opcode);
3213 code = realloc_code (cfg, max_len);
3215 mono_debug_record_line_number (cfg, ins, offset);
3216 if (cfg->verbose_level > 2) {
3217 g_print (" @ 0x%x\t", offset);
3218 mono_print_ins_index (ins_cnt++, ins);
3220 /* Check for virtual regs that snuck by */
3221 g_assert ((ins->dreg >= -1) && (ins->dreg < 32));
3223 switch (ins->opcode) {
3224 case OP_RELAXED_NOP:
3225 case OP_NOP:
3226 case OP_DUMMY_USE:
3227 case OP_DUMMY_ICONST:
3228 case OP_DUMMY_I8CONST:
3229 case OP_DUMMY_R8CONST:
3230 case OP_DUMMY_R4CONST:
3231 case OP_NOT_REACHED:
3232 case OP_NOT_NULL:
3233 break;
3234 case OP_IL_SEQ_POINT:
3235 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3236 break;
3237 case OP_SEQ_POINT: {
3238 if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
3239 guint32 addr = (guint32)ss_trigger_page;
3241 mips_load_const (code, mips_t9, addr);
3242 mips_lw (code, mips_t9, mips_t9, 0);
3245 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3248 * A placeholder for a possible breakpoint inserted by
3249 * mono_arch_set_breakpoint ().
3251 /* mips_load_const () + mips_lw */
3252 mips_nop (code);
3253 mips_nop (code);
3254 mips_nop (code);
3255 break;
3257 case OP_BIGMUL:
3258 mips_mult (code, ins->sreg1, ins->sreg2);
3259 mips_mflo (code, ins->dreg);
3260 mips_mfhi (code, ins->dreg+1);
3261 break;
3262 case OP_BIGMUL_UN:
3263 mips_multu (code, ins->sreg1, ins->sreg2);
3264 mips_mflo (code, ins->dreg);
3265 mips_mfhi (code, ins->dreg+1);
3266 break;
3267 case OP_MEMORY_BARRIER:
3268 mips_sync (code, 0);
3269 break;
3270 case OP_STOREI1_MEMBASE_IMM:
3271 mips_load_const (code, mips_temp, ins->inst_imm);
3272 if (mips_is_imm16 (ins->inst_offset)) {
3273 mips_sb (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3274 } else {
3275 mips_load_const (code, mips_at, ins->inst_offset);
3276 mips_sb (code, mips_temp, mips_at, ins->inst_destbasereg);
3278 break;
3279 case OP_STOREI2_MEMBASE_IMM:
3280 mips_load_const (code, mips_temp, ins->inst_imm);
3281 if (mips_is_imm16 (ins->inst_offset)) {
3282 mips_sh (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3283 } else {
3284 mips_load_const (code, mips_at, ins->inst_offset);
3285 mips_sh (code, mips_temp, mips_at, ins->inst_destbasereg);
3287 break;
3288 case OP_STOREI8_MEMBASE_IMM:
3289 mips_load_const (code, mips_temp, ins->inst_imm);
3290 if (mips_is_imm16 (ins->inst_offset)) {
3291 mips_sd (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3292 } else {
3293 mips_load_const (code, mips_at, ins->inst_offset);
3294 mips_sd (code, mips_temp, mips_at, ins->inst_destbasereg);
3296 break;
3297 case OP_STORE_MEMBASE_IMM:
3298 case OP_STOREI4_MEMBASE_IMM:
3299 mips_load_const (code, mips_temp, ins->inst_imm);
3300 if (mips_is_imm16 (ins->inst_offset)) {
3301 mips_sw (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3302 } else {
3303 mips_load_const (code, mips_at, ins->inst_offset);
3304 mips_sw (code, mips_temp, mips_at, ins->inst_destbasereg);
3306 break;
3307 case OP_STOREI1_MEMBASE_REG:
3308 if (mips_is_imm16 (ins->inst_offset)) {
3309 mips_sb (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3310 } else {
3311 mips_load_const (code, mips_at, ins->inst_offset);
3312 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3313 mips_sb (code, ins->sreg1, mips_at, 0);
3315 break;
3316 case OP_STOREI2_MEMBASE_REG:
3317 if (mips_is_imm16 (ins->inst_offset)) {
3318 mips_sh (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3319 } else {
3320 mips_load_const (code, mips_at, ins->inst_offset);
3321 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3322 mips_sh (code, ins->sreg1, mips_at, 0);
3324 break;
3325 case OP_STORE_MEMBASE_REG:
3326 case OP_STOREI4_MEMBASE_REG:
3327 if (mips_is_imm16 (ins->inst_offset)) {
3328 mips_sw (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3329 } else {
3330 mips_load_const (code, mips_at, ins->inst_offset);
3331 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3332 mips_sw (code, ins->sreg1, mips_at, 0);
3334 break;
3335 case OP_STOREI8_MEMBASE_REG:
3336 if (mips_is_imm16 (ins->inst_offset)) {
3337 mips_sd (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3338 } else {
3339 mips_load_const (code, mips_at, ins->inst_offset);
3340 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3341 mips_sd (code, ins->sreg1, mips_at, 0);
3343 break;
3344 case OP_LOADU4_MEM:
3345 g_assert_not_reached ();
3346 //x86_mov_reg_imm (code, ins->dreg, ins->inst_p0);
3347 //x86_mov_reg_membase (code, ins->dreg, ins->dreg, 0, 4);
3348 break;
3349 case OP_LOADI8_MEMBASE:
3350 if (mips_is_imm16 (ins->inst_offset)) {
3351 mips_ld (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3352 } else {
3353 mips_load_const (code, mips_at, ins->inst_offset);
3354 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3355 mips_ld (code, ins->dreg, mips_at, 0);
3357 break;
3358 case OP_LOAD_MEMBASE:
3359 case OP_LOADI4_MEMBASE:
3360 case OP_LOADU4_MEMBASE:
3361 g_assert (ins->dreg != -1);
3362 if (mips_is_imm16 (ins->inst_offset)) {
3363 mips_lw (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3364 } else {
3365 mips_load_const (code, mips_at, ins->inst_offset);
3366 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3367 mips_lw (code, ins->dreg, mips_at, 0);
3369 break;
3370 case OP_LOADI1_MEMBASE:
3371 if (mips_is_imm16 (ins->inst_offset)) {
3372 mips_lb (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3373 } else {
3374 mips_load_const (code, mips_at, ins->inst_offset);
3375 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3376 mips_lb (code, ins->dreg, mips_at, 0);
3378 break;
3379 case OP_LOADU1_MEMBASE:
3380 if (mips_is_imm16 (ins->inst_offset)) {
3381 mips_lbu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3382 } else {
3383 mips_load_const (code, mips_at, ins->inst_offset);
3384 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3385 mips_lbu (code, ins->dreg, mips_at, 0);
3387 break;
3388 case OP_LOADI2_MEMBASE:
3389 if (mips_is_imm16 (ins->inst_offset)) {
3390 mips_lh (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3391 } else {
3392 mips_load_const (code, mips_at, ins->inst_offset);
3393 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3394 mips_lh (code, ins->dreg, mips_at, 0);
3396 break;
3397 case OP_LOADU2_MEMBASE:
3398 if (mips_is_imm16 (ins->inst_offset)) {
3399 mips_lhu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3400 } else {
3401 mips_load_const (code, mips_at, ins->inst_offset);
3402 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3403 mips_lhu (code, ins->dreg, mips_at, 0);
3405 break;
3406 case OP_ICONV_TO_I1:
3407 mips_sll (code, mips_at, ins->sreg1, 24);
3408 mips_sra (code, ins->dreg, mips_at, 24);
3409 break;
3410 case OP_ICONV_TO_I2:
3411 mips_sll (code, mips_at, ins->sreg1, 16);
3412 mips_sra (code, ins->dreg, mips_at, 16);
3413 break;
3414 case OP_ICONV_TO_U1:
3415 mips_andi (code, ins->dreg, ins->sreg1, 0xff);
3416 break;
3417 case OP_ICONV_TO_U2:
3418 mips_sll (code, mips_at, ins->sreg1, 16);
3419 mips_srl (code, ins->dreg, mips_at, 16);
3420 break;
3421 case OP_MIPS_SLT:
3422 mips_slt (code, ins->dreg, ins->sreg1, ins->sreg2);
3423 break;
3424 case OP_MIPS_SLTI:
3425 g_assert (mips_is_imm16 (ins->inst_imm));
3426 mips_slti (code, ins->dreg, ins->sreg1, ins->inst_imm);
3427 break;
3428 case OP_MIPS_SLTU:
3429 mips_sltu (code, ins->dreg, ins->sreg1, ins->sreg2);
3430 break;
3431 case OP_MIPS_SLTIU:
3432 g_assert (mips_is_imm16 (ins->inst_imm));
3433 mips_sltiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3434 break;
3435 case OP_BREAK:
3437 * gdb does not like encountering the hw breakpoint ins in the debugged code.
3438 * So instead of emitting a trap, we emit a call a C function and place a
3439 * breakpoint there.
3441 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_JIT_ICALL_ID, GUINT_TO_POINTER (MONO_JIT_ICALL_mono_break));
3442 mips_load (code, mips_t9, 0x1f1f1f1f);
3443 mips_jalr (code, mips_t9, mips_ra);
3444 mips_nop (code);
3445 break;
3446 case OP_IADD:
3447 mips_addu (code, ins->dreg, ins->sreg1, ins->sreg2);
3448 break;
3449 case OP_LADD:
3450 mips_daddu (code, ins->dreg, ins->sreg1, ins->sreg2);
3451 break;
3453 case OP_ADD_IMM:
3454 case OP_IADD_IMM:
3455 g_assert (mips_is_imm16 (ins->inst_imm));
3456 mips_addiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3457 break;
3458 case OP_LADD_IMM:
3459 g_assert (mips_is_imm16 (ins->inst_imm));
3460 mips_daddiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3461 break;
3463 case OP_ISUB:
3464 mips_subu (code, ins->dreg, ins->sreg1, ins->sreg2);
3465 break;
3466 case OP_LSUB:
3467 mips_dsubu (code, ins->dreg, ins->sreg1, ins->sreg2);
3468 break;
3470 case OP_ISUB_IMM:
3471 case OP_SUB_IMM:
3472 // we add the negated value
3473 g_assert (mips_is_imm16 (-ins->inst_imm));
3474 mips_addiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3475 break;
3477 case OP_LSUB_IMM:
3478 // we add the negated value
3479 g_assert (mips_is_imm16 (-ins->inst_imm));
3480 mips_daddiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3481 break;
3483 case OP_IAND:
3484 case OP_LAND:
3485 mips_and (code, ins->dreg, ins->sreg1, ins->sreg2);
3486 break;
3488 case OP_AND_IMM:
3489 case OP_IAND_IMM:
3490 case OP_LAND_IMM:
3491 g_assert (!(ins->inst_imm & 0xffff0000));
3492 mips_andi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3493 break;
3495 case OP_IDIV:
3496 case OP_IREM: {
3497 guint32 *divisor_is_m1;
3498 guint32 *dividend_is_minvalue;
3499 guint32 *divisor_is_zero;
3501 mips_load_const (code, mips_at, -1);
3502 divisor_is_m1 = (guint32 *)(void *)code;
3503 mips_bne (code, ins->sreg2, mips_at, 0);
3504 mips_lui (code, mips_at, mips_zero, 0x8000);
3505 dividend_is_minvalue = (guint32 *)(void *)code;
3506 mips_bne (code, ins->sreg1, mips_at, 0);
3507 mips_nop (code);
3509 /* Divide Int32.MinValue by -1 -- throw exception */
3510 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3512 mips_patch (divisor_is_m1, (guint32)code);
3513 mips_patch (dividend_is_minvalue, (guint32)code);
3515 /* Put divide in branch delay slot (NOT YET) */
3516 divisor_is_zero = (guint32 *)(void *)code;
3517 mips_bne (code, ins->sreg2, mips_zero, 0);
3518 mips_nop (code);
3520 /* Divide by zero -- throw exception */
3521 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3523 mips_patch (divisor_is_zero, (guint32)code);
3524 mips_div (code, ins->sreg1, ins->sreg2);
3525 if (ins->opcode == OP_IDIV)
3526 mips_mflo (code, ins->dreg);
3527 else
3528 mips_mfhi (code, ins->dreg);
3529 break;
3531 case OP_IDIV_UN:
3532 case OP_IREM_UN: {
3533 guint32 *divisor_is_zero = (guint32 *)(void *)code;
3535 /* Put divide in branch delay slot (NOT YET) */
3536 mips_bne (code, ins->sreg2, mips_zero, 0);
3537 mips_nop (code);
3539 /* Divide by zero -- throw exception */
3540 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3542 mips_patch (divisor_is_zero, (guint32)code);
3543 mips_divu (code, ins->sreg1, ins->sreg2);
3544 if (ins->opcode == OP_IDIV_UN)
3545 mips_mflo (code, ins->dreg);
3546 else
3547 mips_mfhi (code, ins->dreg);
3548 break;
3550 case OP_DIV_IMM:
3551 g_assert_not_reached ();
3552 #if 0
3553 ppc_load (code, ppc_r12, ins->inst_imm);
3554 ppc_divwod (code, ins->dreg, ins->sreg1, ppc_r12);
3555 ppc_mfspr (code, ppc_r0, ppc_xer);
3556 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3557 /* FIXME: use OverflowException for 0x80000000/-1 */
3558 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3559 #endif
3560 g_assert_not_reached();
3561 break;
3562 case OP_REM_IMM:
3563 g_assert_not_reached ();
3564 case OP_IOR:
3565 mips_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3566 break;
3567 case OP_OR_IMM:
3568 case OP_IOR_IMM:
3569 g_assert (!(ins->inst_imm & 0xffff0000));
3570 mips_ori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3571 break;
3572 case OP_IXOR:
3573 mips_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3574 break;
3575 case OP_XOR_IMM:
3576 case OP_IXOR_IMM:
3577 /* unsigned 16-bit immediate */
3578 g_assert (!(ins->inst_imm & 0xffff0000));
3579 mips_xori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3580 break;
3581 case OP_ISHL:
3582 mips_sllv (code, ins->dreg, ins->sreg1, ins->sreg2);
3583 break;
3584 case OP_SHL_IMM:
3585 case OP_ISHL_IMM:
3586 mips_sll (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3587 break;
3588 case OP_ISHR:
3589 mips_srav (code, ins->dreg, ins->sreg1, ins->sreg2);
3590 break;
3591 case OP_LSHR:
3592 mips_dsrav (code, ins->dreg, ins->sreg1, ins->sreg2);
3593 break;
3594 case OP_SHR_IMM:
3595 case OP_ISHR_IMM:
3596 mips_sra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3597 break;
3598 case OP_LSHR_IMM:
3599 mips_dsra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3600 break;
3601 case OP_SHR_UN_IMM:
3602 case OP_ISHR_UN_IMM:
3603 mips_srl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3604 break;
3605 case OP_LSHR_UN_IMM:
3606 mips_dsrl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3607 break;
3608 case OP_ISHR_UN:
3609 mips_srlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3610 break;
3611 case OP_LSHR_UN:
3612 mips_dsrlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3613 break;
3614 case OP_INOT:
3615 case OP_LNOT:
3616 mips_nor (code, ins->dreg, mips_zero, ins->sreg1);
3617 break;
3618 case OP_INEG:
3619 mips_subu (code, ins->dreg, mips_zero, ins->sreg1);
3620 break;
3621 case OP_LNEG:
3622 mips_dsubu (code, ins->dreg, mips_zero, ins->sreg1);
3623 break;
3624 case OP_IMUL:
3625 #if USE_MUL
3626 mips_mul (code, ins->dreg, ins->sreg1, ins->sreg2);
3627 #else
3628 mips_mult (code, ins->sreg1, ins->sreg2);
3629 mips_mflo (code, ins->dreg);
3630 mips_nop (code);
3631 mips_nop (code);
3632 #endif
3633 break;
3634 #if SIZEOF_REGISTER == 8
3635 case OP_LMUL:
3636 mips_dmult (code, ins->sreg1, ins->sreg2);
3637 mips_mflo (code, ins->dreg);
3638 break;
3639 #endif
3640 case OP_IMUL_OVF: {
3641 guint32 *patch;
3642 mips_mult (code, ins->sreg1, ins->sreg2);
3643 mips_mflo (code, ins->dreg);
3644 mips_mfhi (code, mips_at);
3645 mips_nop (code);
3646 mips_nop (code);
3647 mips_sra (code, mips_temp, ins->dreg, 31);
3648 patch = (guint32 *)(void *)code;
3649 mips_beq (code, mips_temp, mips_at, 0);
3650 mips_nop (code);
3651 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3652 mips_patch (patch, (guint32)code);
3653 break;
3655 case OP_IMUL_OVF_UN: {
3656 guint32 *patch;
3657 mips_mult (code, ins->sreg1, ins->sreg2);
3658 mips_mflo (code, ins->dreg);
3659 mips_mfhi (code, mips_at);
3660 mips_nop (code);
3661 mips_nop (code);
3662 patch = (guint32 *)(void *)code;
3663 mips_beq (code, mips_at, mips_zero, 0);
3664 mips_nop (code);
3665 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3666 mips_patch (patch, (guint32)code);
3667 break;
3669 case OP_ICONST:
3670 mips_load_const (code, ins->dreg, ins->inst_c0);
3671 break;
3672 #if SIZEOF_REGISTER == 8
3673 case OP_I8CONST:
3674 mips_load_const (code, ins->dreg, ins->inst_c0);
3675 break;
3676 #endif
3677 case OP_AOTCONST:
3678 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3679 mips_load (code, ins->dreg, 0);
3680 break;
3682 case OP_MIPS_MTC1S:
3683 mips_mtc1 (code, ins->dreg, ins->sreg1);
3684 break;
3685 case OP_MIPS_MTC1S_2:
3686 mips_mtc1 (code, ins->dreg, ins->sreg1);
3687 mips_mtc1 (code, ins->dreg+1, ins->sreg2);
3688 break;
3689 case OP_MIPS_MFC1S:
3690 mips_mfc1 (code, ins->dreg, ins->sreg1);
3691 break;
3692 case OP_MIPS_MTC1D:
3693 mips_dmtc1 (code, ins->dreg, ins->sreg1);
3694 break;
3695 case OP_MIPS_MFC1D:
3696 #if 0
3697 mips_dmfc1 (code, ins->dreg, ins->sreg1);
3698 #else
3699 mips_mfc1 (code, ins->dreg, ins->sreg1 + ls_word_idx);
3700 mips_mfc1 (code, ins->dreg+1, ins->sreg1 + ms_word_idx);
3701 #endif
3702 break;
3704 case OP_ICONV_TO_I4:
3705 case OP_ICONV_TO_U4:
3706 case OP_MOVE:
3707 if (ins->dreg != ins->sreg1)
3708 MIPS_MOVE (code, ins->dreg, ins->sreg1);
3709 break;
3710 #if SIZEOF_REGISTER == 8
3711 case OP_ZEXT_I4:
3712 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3713 mips_dsrl (code, ins->dreg, ins->dreg, 32);
3714 break;
3715 case OP_SEXT_I4:
3716 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3717 mips_dsra (code, ins->dreg, ins->dreg, 32);
3718 break;
3719 #endif
3720 case OP_SETLRET: {
3721 int lsreg = mips_v0 + ls_word_idx;
3722 int msreg = mips_v0 + ms_word_idx;
3724 /* Get sreg1 into lsreg, sreg2 into msreg */
3726 if (ins->sreg1 == msreg) {
3727 if (ins->sreg1 != mips_at)
3728 MIPS_MOVE (code, mips_at, ins->sreg1);
3729 if (ins->sreg2 != msreg)
3730 MIPS_MOVE (code, msreg, ins->sreg2);
3731 MIPS_MOVE (code, lsreg, mips_at);
3733 else {
3734 if (ins->sreg2 != msreg)
3735 MIPS_MOVE (code, msreg, ins->sreg2);
3736 if (ins->sreg1 != lsreg)
3737 MIPS_MOVE (code, lsreg, ins->sreg1);
3739 break;
3741 case OP_FMOVE:
3742 if (ins->dreg != ins->sreg1) {
3743 mips_fmovd (code, ins->dreg, ins->sreg1);
3745 break;
3746 case OP_MOVE_F_TO_I4:
3747 mips_cvtsd (code, mips_ftemp, ins->sreg1);
3748 mips_mfc1 (code, ins->dreg, mips_ftemp);
3749 break;
3750 case OP_MOVE_I4_TO_F:
3751 mips_mtc1 (code, ins->dreg, ins->sreg1);
3752 mips_cvtds (code, ins->dreg, ins->dreg);
3753 break;
3754 case OP_MIPS_CVTSD:
3755 /* Convert from double to float and leave it there */
3756 mips_cvtsd (code, ins->dreg, ins->sreg1);
3757 break;
3758 case OP_FCONV_TO_R4:
3759 #if 0
3760 mips_cvtsd (code, ins->dreg, ins->sreg1);
3761 #else
3762 /* Just a move, no precision change */
3763 if (ins->dreg != ins->sreg1) {
3764 mips_fmovd (code, ins->dreg, ins->sreg1);
3766 #endif
3767 break;
3768 case OP_CHECK_THIS:
3769 /* ensure ins->sreg1 is not NULL */
3770 mips_lw (code, mips_zero, ins->sreg1, 0);
3771 break;
3772 case OP_ARGLIST: {
3773 g_assert (mips_is_imm16 (cfg->sig_cookie));
3774 mips_lw (code, mips_at, cfg->frame_reg, cfg->sig_cookie);
3775 mips_sw (code, mips_at, ins->sreg1, 0);
3776 break;
3778 case OP_FCALL:
3779 case OP_LCALL:
3780 case OP_VCALL:
3781 case OP_VCALL2:
3782 case OP_VOIDCALL:
3783 case OP_CALL:
3784 case OP_FCALL_REG:
3785 case OP_LCALL_REG:
3786 case OP_VCALL_REG:
3787 case OP_VCALL2_REG:
3788 case OP_VOIDCALL_REG:
3789 case OP_CALL_REG:
3790 case OP_FCALL_MEMBASE:
3791 case OP_LCALL_MEMBASE:
3792 case OP_VCALL_MEMBASE:
3793 case OP_VCALL2_MEMBASE:
3794 case OP_VOIDCALL_MEMBASE:
3795 case OP_CALL_MEMBASE:
3796 call = (MonoCallInst*)ins;
3797 switch (ins->opcode) {
3798 case OP_FCALL:
3799 case OP_LCALL:
3800 case OP_VCALL:
3801 case OP_VCALL2:
3802 case OP_VOIDCALL:
3803 case OP_CALL:
3804 mono_call_add_patch_info (cfg, call, offset);
3805 if (ins->flags & MONO_INST_HAS_METHOD) {
3806 mips_load (code, mips_t9, call->method);
3808 else {
3809 mips_load (code, mips_t9, call->fptr);
3811 mips_jalr (code, mips_t9, mips_ra);
3812 mips_nop (code);
3813 break;
3814 case OP_FCALL_REG:
3815 case OP_LCALL_REG:
3816 case OP_VCALL_REG:
3817 case OP_VCALL2_REG:
3818 case OP_VOIDCALL_REG:
3819 case OP_CALL_REG:
3820 MIPS_MOVE (code, mips_t9, ins->sreg1);
3821 mips_jalr (code, mips_t9, mips_ra);
3822 mips_nop (code);
3823 break;
3824 case OP_FCALL_MEMBASE:
3825 case OP_LCALL_MEMBASE:
3826 case OP_VCALL_MEMBASE:
3827 case OP_VCALL2_MEMBASE:
3828 case OP_VOIDCALL_MEMBASE:
3829 case OP_CALL_MEMBASE:
3830 mips_lw (code, mips_t9, ins->sreg1, ins->inst_offset);
3831 mips_jalr (code, mips_t9, mips_ra);
3832 mips_nop (code);
3833 break;
3835 #if PROMOTE_R4_TO_R8
3836 /* returned an FP R4 (single), promote to R8 (double) in place */
3837 switch (ins->opcode) {
3838 case OP_FCALL:
3839 case OP_FCALL_REG:
3840 case OP_FCALL_MEMBASE:
3841 if (call->signature->ret->type == MONO_TYPE_R4)
3842 mips_cvtds (code, mips_f0, mips_f0);
3843 break;
3844 default:
3845 break;
3847 #endif
3848 break;
3849 case OP_LOCALLOC: {
3850 int area_offset = cfg->param_area;
3852 /* Round up ins->sreg1, mips_at ends up holding size */
3853 mips_addiu (code, mips_at, ins->sreg1, 31);
3854 mips_addiu (code, mips_temp, mips_zero, ~31);
3855 mips_and (code, mips_at, mips_at, mips_temp);
3857 mips_subu (code, mips_sp, mips_sp, mips_at);
3858 g_assert (mips_is_imm16 (area_offset));
3859 mips_addiu (code, ins->dreg, mips_sp, area_offset);
3861 if (ins->flags & MONO_INST_INIT) {
3862 guint32 *buf;
3864 buf = (guint32*)(void*)code;
3865 mips_beq (code, mips_at, mips_zero, 0);
3866 mips_nop (code);
3868 mips_move (code, mips_temp, ins->dreg);
3869 mips_sb (code, mips_zero, mips_temp, 0);
3870 mips_addiu (code, mips_at, mips_at, -1);
3871 mips_bne (code, mips_at, mips_zero, -3);
3872 mips_addiu (code, mips_temp, mips_temp, 1);
3874 mips_patch (buf, (guint32)code);
3876 break;
3878 case OP_THROW: {
3879 gpointer addr = mono_arch_get_throw_exception(NULL, FALSE);
3880 mips_move (code, mips_a0, ins->sreg1);
3881 mips_call (code, mips_t9, addr);
3882 mips_break (code, 0xfc);
3883 break;
3885 case OP_RETHROW: {
3886 gpointer addr = mono_arch_get_rethrow_exception(NULL, FALSE);
3887 mips_move (code, mips_a0, ins->sreg1);
3888 mips_call (code, mips_t9, addr);
3889 mips_break (code, 0xfb);
3890 break;
3892 case OP_START_HANDLER: {
3894 * The START_HANDLER instruction marks the beginning of
3895 * a handler block. It is called using a call
3896 * instruction, so mips_ra contains the return address.
3897 * Since the handler executes in the same stack frame
3898 * as the method itself, we can't use save/restore to
3899 * save the return address. Instead, we save it into
3900 * a dedicated variable.
3902 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3903 g_assert (spvar->inst_basereg != mips_sp);
3904 code = emit_reserve_param_area (cfg, code);
3906 if (mips_is_imm16 (spvar->inst_offset)) {
3907 mips_sw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
3908 } else {
3909 mips_load_const (code, mips_at, spvar->inst_offset);
3910 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
3911 mips_sw (code, mips_ra, mips_at, 0);
3913 break;
3915 case OP_ENDFILTER: {
3916 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3917 g_assert (spvar->inst_basereg != mips_sp);
3918 code = emit_unreserve_param_area (cfg, code);
3920 if (ins->sreg1 != mips_v0)
3921 MIPS_MOVE (code, mips_v0, ins->sreg1);
3922 if (mips_is_imm16 (spvar->inst_offset)) {
3923 mips_lw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
3924 } else {
3925 mips_load_const (code, mips_at, spvar->inst_offset);
3926 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
3927 mips_lw (code, mips_ra, mips_at, 0);
3929 mips_jr (code, mips_ra);
3930 mips_nop (code);
3931 break;
3933 case OP_ENDFINALLY: {
3934 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3935 g_assert (spvar->inst_basereg != mips_sp);
3936 code = emit_unreserve_param_area (cfg, code);
3937 mips_lw (code, mips_t9, spvar->inst_basereg, spvar->inst_offset);
3938 mips_jalr (code, mips_t9, mips_ra);
3939 mips_nop (code);
3940 break;
3942 case OP_CALL_HANDLER:
3943 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3944 mips_lui (code, mips_t9, mips_zero, 0);
3945 mips_addiu (code, mips_t9, mips_t9, 0);
3946 mips_jalr (code, mips_t9, mips_ra);
3947 mips_nop (code);
3948 /*FIXME should it be before the NOP or not? Does MIPS has a delay slot like sparc?*/
3949 for (GList *tmp = ins->inst_eh_blocks; tmp != bb->clause_holes; tmp = tmp->prev)
3950 mono_cfg_add_try_hole (cfg, ((MonoLeaveClause *) tmp->data)->clause, code, bb);
3951 break;
3952 case OP_LABEL:
3953 ins->inst_c0 = code - cfg->native_code;
3954 break;
3955 case OP_BR:
3956 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3957 if (cfg->arch.long_branch) {
3958 mips_lui (code, mips_at, mips_zero, 0);
3959 mips_addiu (code, mips_at, mips_at, 0);
3960 mips_jr (code, mips_at);
3961 mips_nop (code);
3963 else {
3964 mips_beq (code, mips_zero, mips_zero, 0);
3965 mips_nop (code);
3967 break;
3968 case OP_BR_REG:
3969 mips_jr (code, ins->sreg1);
3970 mips_nop (code);
3971 break;
3972 case OP_SWITCH: {
3973 int i;
3975 max_len += 4 * GPOINTER_TO_INT (ins->klass);
3976 code = realloc_code (cfg, max_len);
3978 g_assert (ins->sreg1 != -1);
3979 mips_sll (code, mips_at, ins->sreg1, 2);
3980 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS))
3981 MIPS_MOVE (code, mips_t8, mips_ra);
3982 mips_bgezal (code, mips_zero, 1); /* bal */
3983 mips_nop (code);
3984 mips_addu (code, mips_t9, mips_ra, mips_at);
3985 /* Table is 16 or 20 bytes from target of bal above */
3986 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS)) {
3987 MIPS_MOVE (code, mips_ra, mips_t8);
3988 mips_lw (code, mips_t9, mips_t9, 20);
3990 else
3991 mips_lw (code, mips_t9, mips_t9, 16);
3992 mips_jalr (code, mips_t9, mips_t8);
3993 mips_nop (code);
3994 for (i = 0; i < GPOINTER_TO_INT (ins->klass); ++i)
3995 mips_emit32 (code, 0xfefefefe);
3996 break;
3998 case OP_CEQ:
3999 case OP_ICEQ:
4000 mips_addiu (code, ins->dreg, mips_zero, 1);
4001 mips_beq (code, mips_at, mips_zero, 2);
4002 mips_nop (code);
4003 MIPS_MOVE (code, ins->dreg, mips_zero);
4004 break;
4005 case OP_CLT:
4006 case OP_CLT_UN:
4007 case OP_ICLT:
4008 case OP_ICLT_UN:
4009 mips_addiu (code, ins->dreg, mips_zero, 1);
4010 mips_bltz (code, mips_at, 2);
4011 mips_nop (code);
4012 MIPS_MOVE (code, ins->dreg, mips_zero);
4013 break;
4014 case OP_CGT:
4015 case OP_CGT_UN:
4016 case OP_ICGT:
4017 case OP_ICGT_UN:
4018 mips_addiu (code, ins->dreg, mips_zero, 1);
4019 mips_bgtz (code, mips_at, 2);
4020 mips_nop (code);
4021 MIPS_MOVE (code, ins->dreg, mips_zero);
4022 break;
4024 case OP_MIPS_COND_EXC_EQ:
4025 case OP_MIPS_COND_EXC_GE:
4026 case OP_MIPS_COND_EXC_GT:
4027 case OP_MIPS_COND_EXC_LE:
4028 case OP_MIPS_COND_EXC_LT:
4029 case OP_MIPS_COND_EXC_NE_UN:
4030 case OP_MIPS_COND_EXC_GE_UN:
4031 case OP_MIPS_COND_EXC_GT_UN:
4032 case OP_MIPS_COND_EXC_LE_UN:
4033 case OP_MIPS_COND_EXC_LT_UN:
4035 case OP_MIPS_COND_EXC_OV:
4036 case OP_MIPS_COND_EXC_NO:
4037 case OP_MIPS_COND_EXC_C:
4038 case OP_MIPS_COND_EXC_NC:
4040 case OP_MIPS_COND_EXC_IEQ:
4041 case OP_MIPS_COND_EXC_IGE:
4042 case OP_MIPS_COND_EXC_IGT:
4043 case OP_MIPS_COND_EXC_ILE:
4044 case OP_MIPS_COND_EXC_ILT:
4045 case OP_MIPS_COND_EXC_INE_UN:
4046 case OP_MIPS_COND_EXC_IGE_UN:
4047 case OP_MIPS_COND_EXC_IGT_UN:
4048 case OP_MIPS_COND_EXC_ILE_UN:
4049 case OP_MIPS_COND_EXC_ILT_UN:
4051 case OP_MIPS_COND_EXC_IOV:
4052 case OP_MIPS_COND_EXC_INO:
4053 case OP_MIPS_COND_EXC_IC:
4054 case OP_MIPS_COND_EXC_INC: {
4055 guint32 *skip;
4056 guint32 *throw;
4058 /* If the condition is true, raise the exception */
4060 /* need to reverse test to skip around exception raising */
4062 /* For the moment, branch around a branch to avoid reversing
4063 the tests. */
4065 /* Remember, an unpatched branch to 0 branches to the delay slot */
4066 switch (ins->opcode) {
4067 case OP_MIPS_COND_EXC_EQ:
4068 throw = (guint32 *)(void *)code;
4069 mips_beq (code, ins->sreg1, ins->sreg2, 0);
4070 mips_nop (code);
4071 break;
4073 case OP_MIPS_COND_EXC_NE_UN:
4074 throw = (guint32 *)(void *)code;
4075 mips_bne (code, ins->sreg1, ins->sreg2, 0);
4076 mips_nop (code);
4077 break;
4079 case OP_MIPS_COND_EXC_LE_UN:
4080 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
4081 throw = (guint32 *)(void *)code;
4082 mips_beq (code, mips_at, mips_zero, 0);
4083 mips_nop (code);
4084 break;
4086 case OP_MIPS_COND_EXC_GT:
4087 mips_slt (code, mips_at, ins->sreg2, ins->sreg1);
4088 throw = (guint32 *)(void *)code;
4089 mips_bne (code, mips_at, mips_zero, 0);
4090 mips_nop (code);
4091 break;
4093 case OP_MIPS_COND_EXC_GT_UN:
4094 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
4095 throw = (guint32 *)(void *)code;
4096 mips_bne (code, mips_at, mips_zero, 0);
4097 mips_nop (code);
4098 break;
4100 case OP_MIPS_COND_EXC_LT:
4101 mips_slt (code, mips_at, ins->sreg1, ins->sreg2);
4102 throw = (guint32 *)(void *)code;
4103 mips_bne (code, mips_at, mips_zero, 0);
4104 mips_nop (code);
4105 break;
4107 case OP_MIPS_COND_EXC_LT_UN:
4108 mips_sltu (code, mips_at, ins->sreg1, ins->sreg2);
4109 throw = (guint32 *)(void *)code;
4110 mips_bne (code, mips_at, mips_zero, 0);
4111 mips_nop (code);
4112 break;
4114 default:
4115 /* Not yet implemented */
4116 g_warning ("NYI conditional exception %s\n", mono_inst_name (ins->opcode));
4117 g_assert_not_reached ();
4119 skip = (guint32 *)(void *)code;
4120 mips_beq (code, mips_zero, mips_zero, 0);
4121 mips_nop (code);
4122 mips_patch (throw, (guint32)code);
4123 code = mips_emit_exc_by_name (code, ins->inst_p1);
4124 mips_patch (skip, (guint32)code);
4125 cfg->bb_exit->max_offset += 24;
4126 break;
4128 case OP_MIPS_BEQ:
4129 case OP_MIPS_BNE:
4130 case OP_MIPS_BGEZ:
4131 case OP_MIPS_BGTZ:
4132 case OP_MIPS_BLEZ:
4133 case OP_MIPS_BLTZ:
4134 code = mips_emit_cond_branch (cfg, code, ins->opcode, ins);
4135 break;
4137 /* floating point opcodes */
4138 case OP_R8CONST:
4139 #if 0
4140 if (((guint32)ins->inst_p0) & (1 << 15))
4141 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4142 else
4143 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4144 mips_ldc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4145 #else
4146 mips_load_const (code, mips_at, ins->inst_p0);
4147 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4148 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4149 #endif
4150 break;
4151 case OP_R4CONST:
4152 if (((guint32)ins->inst_p0) & (1 << 15))
4153 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4154 else
4155 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4156 mips_lwc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4157 #if PROMOTE_R4_TO_R8
4158 mips_cvtds (code, ins->dreg, ins->dreg);
4159 #endif
4160 break;
4161 case OP_STORER8_MEMBASE_REG:
4162 if (mips_is_imm16 (ins->inst_offset)) {
4163 #if _MIPS_SIM == _ABIO32
4164 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset + ls_word_offset);
4165 mips_swc1 (code, ins->sreg1+1, ins->inst_destbasereg, ins->inst_offset + ms_word_offset);
4166 #elif _MIPS_SIM == _ABIN32
4167 mips_sdc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4168 #endif
4169 } else {
4170 mips_load_const (code, mips_at, ins->inst_offset);
4171 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
4172 mips_swc1 (code, ins->sreg1, mips_at, ls_word_offset);
4173 mips_swc1 (code, ins->sreg1+1, mips_at, ms_word_offset);
4175 break;
4176 case OP_LOADR8_MEMBASE:
4177 if (mips_is_imm16 (ins->inst_offset)) {
4178 #if _MIPS_SIM == _ABIO32
4179 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset + ls_word_offset);
4180 mips_lwc1 (code, ins->dreg+1, ins->inst_basereg, ins->inst_offset + ms_word_offset);
4181 #elif _MIPS_SIM == _ABIN32
4182 mips_ldc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4183 #endif
4184 } else {
4185 mips_load_const (code, mips_at, ins->inst_offset);
4186 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
4187 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4188 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4190 break;
4191 case OP_STORER4_MEMBASE_REG:
4192 g_assert (mips_is_imm16 (ins->inst_offset));
4193 #if PROMOTE_R4_TO_R8
4194 /* Need to convert ins->sreg1 to single-precision first */
4195 mips_cvtsd (code, mips_ftemp, ins->sreg1);
4196 mips_swc1 (code, mips_ftemp, ins->inst_destbasereg, ins->inst_offset);
4197 #else
4198 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4199 #endif
4200 break;
4201 case OP_MIPS_LWC1:
4202 g_assert (mips_is_imm16 (ins->inst_offset));
4203 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4204 break;
4205 case OP_LOADR4_MEMBASE:
4206 g_assert (mips_is_imm16 (ins->inst_offset));
4207 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4208 #if PROMOTE_R4_TO_R8
4209 /* Convert to double precision in place */
4210 mips_cvtds (code, ins->dreg, ins->dreg);
4211 #endif
4212 break;
4213 case OP_LOADR4_MEMINDEX:
4214 mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4215 mips_lwc1 (code, ins->dreg, mips_at, 0);
4216 break;
4217 case OP_LOADR8_MEMINDEX:
4218 mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4219 #if _MIPS_SIM == _ABIO32
4220 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4221 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4222 #elif _MIPS_SIM == _ABIN32
4223 mips_ldc1 (code, ins->dreg, mips_at, 0);
4224 #endif
4225 break;
4226 case OP_STORER4_MEMINDEX:
4227 mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4228 #if PROMOTE_R4_TO_R8
4229 /* Need to convert ins->sreg1 to single-precision first */
4230 mips_cvtsd (code, mips_ftemp, ins->sreg1);
4231 mips_swc1 (code, mips_ftemp, mips_at, 0);
4232 #else
4233 mips_swc1 (code, ins->sreg1, mips_at, 0);
4234 #endif
4235 break;
4236 case OP_STORER8_MEMINDEX:
4237 mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4238 #if _MIPS_SIM == _ABIO32
4239 mips_swc1 (code, ins->sreg1, mips_at, ls_word_offset);
4240 mips_swc1 (code, ins->sreg1+1, mips_at, ms_word_offset);
4241 #elif _MIPS_SIM == _ABIN32
4242 mips_sdc1 (code, ins->sreg1, mips_at, 0);
4243 #endif
4244 break;
4245 case OP_ICONV_TO_R_UN: {
4246 static const guint64 adjust_val = 0x41F0000000000000ULL;
4248 /* convert unsigned int to double */
4249 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4250 mips_bgez (code, ins->sreg1, 5);
4251 mips_cvtdw (code, ins->dreg, mips_ftemp);
4253 mips_load (code, mips_at, (guint32) &adjust_val);
4254 mips_ldc1 (code, mips_ftemp, mips_at, 0);
4255 mips_faddd (code, ins->dreg, ins->dreg, mips_ftemp);
4256 /* target is here */
4257 break;
4259 case OP_ICONV_TO_R4:
4260 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4261 mips_cvtsw (code, ins->dreg, mips_ftemp);
4262 mips_cvtds (code, ins->dreg, ins->dreg);
4263 break;
4264 case OP_ICONV_TO_R8:
4265 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4266 mips_cvtdw (code, ins->dreg, mips_ftemp);
4267 break;
4268 case OP_FCONV_TO_I1:
4269 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4270 break;
4271 case OP_FCONV_TO_U1:
4272 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4273 break;
4274 case OP_FCONV_TO_I2:
4275 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4276 break;
4277 case OP_FCONV_TO_U2:
4278 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4279 break;
4280 case OP_FCONV_TO_I4:
4281 case OP_FCONV_TO_I:
4282 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4283 break;
4284 case OP_FCONV_TO_U4:
4285 case OP_FCONV_TO_U:
4286 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4287 break;
4288 case OP_SQRT:
4289 mips_fsqrtd (code, ins->dreg, ins->sreg1);
4290 break;
4291 case OP_FADD:
4292 mips_faddd (code, ins->dreg, ins->sreg1, ins->sreg2);
4293 break;
4294 case OP_FSUB:
4295 mips_fsubd (code, ins->dreg, ins->sreg1, ins->sreg2);
4296 break;
4297 case OP_FMUL:
4298 mips_fmuld (code, ins->dreg, ins->sreg1, ins->sreg2);
4299 break;
4300 case OP_FDIV:
4301 mips_fdivd (code, ins->dreg, ins->sreg1, ins->sreg2);
4302 break;
4303 case OP_FNEG:
4304 mips_fnegd (code, ins->dreg, ins->sreg1);
4305 break;
4306 case OP_FCEQ:
4307 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
4308 mips_addiu (code, ins->dreg, mips_zero, 1);
4309 mips_fbtrue (code, 2);
4310 mips_nop (code);
4311 MIPS_MOVE (code, ins->dreg, mips_zero);
4312 break;
4313 case OP_FCLT:
4314 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
4315 mips_addiu (code, ins->dreg, mips_zero, 1);
4316 mips_fbtrue (code, 2);
4317 mips_nop (code);
4318 MIPS_MOVE (code, ins->dreg, mips_zero);
4319 break;
4320 case OP_FCLT_UN:
4321 /* Less than, or Unordered */
4322 mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
4323 mips_addiu (code, ins->dreg, mips_zero, 1);
4324 mips_fbtrue (code, 2);
4325 mips_nop (code);
4326 MIPS_MOVE (code, ins->dreg, mips_zero);
4327 break;
4328 case OP_FCGT:
4329 mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
4330 MIPS_MOVE (code, ins->dreg, mips_zero);
4331 mips_fbtrue (code, 2);
4332 mips_nop (code);
4333 mips_addiu (code, ins->dreg, mips_zero, 1);
4334 break;
4335 case OP_FCGT_UN:
4336 /* Greater than, or Unordered */
4337 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
4338 MIPS_MOVE (code, ins->dreg, mips_zero);
4339 mips_fbtrue (code, 2);
4340 mips_nop (code);
4341 mips_addiu (code, ins->dreg, mips_zero, 1);
4342 break;
4343 case OP_MIPS_FBEQ:
4344 case OP_MIPS_FBNE:
4345 case OP_MIPS_FBLT:
4346 case OP_MIPS_FBLT_UN:
4347 case OP_MIPS_FBGT:
4348 case OP_MIPS_FBGT_UN:
4349 case OP_MIPS_FBGE:
4350 case OP_MIPS_FBGE_UN:
4351 case OP_MIPS_FBLE:
4352 case OP_MIPS_FBLE_UN: {
4353 int cond = 0;
4354 gboolean is_true = TRUE, is_ordered = FALSE;
4355 guint32 *buf = NULL;
4357 switch (ins->opcode) {
4358 case OP_MIPS_FBEQ:
4359 cond = MIPS_FPU_EQ;
4360 is_true = TRUE;
4361 break;
4362 case OP_MIPS_FBNE:
4363 cond = MIPS_FPU_EQ;
4364 is_true = FALSE;
4365 break;
4366 case OP_MIPS_FBLT:
4367 cond = MIPS_FPU_LT;
4368 is_true = TRUE;
4369 is_ordered = TRUE;
4370 break;
4371 case OP_MIPS_FBLT_UN:
4372 cond = MIPS_FPU_ULT;
4373 is_true = TRUE;
4374 break;
4375 case OP_MIPS_FBGT:
4376 cond = MIPS_FPU_LE;
4377 is_true = FALSE;
4378 is_ordered = TRUE;
4379 break;
4380 case OP_MIPS_FBGT_UN:
4381 cond = MIPS_FPU_OLE;
4382 is_true = FALSE;
4383 break;
4384 case OP_MIPS_FBGE:
4385 cond = MIPS_FPU_LT;
4386 is_true = FALSE;
4387 is_ordered = TRUE;
4388 break;
4389 case OP_MIPS_FBGE_UN:
4390 cond = MIPS_FPU_OLT;
4391 is_true = FALSE;
4392 break;
4393 case OP_MIPS_FBLE:
4394 cond = MIPS_FPU_OLE;
4395 is_true = TRUE;
4396 is_ordered = TRUE;
4397 break;
4398 case OP_MIPS_FBLE_UN:
4399 cond = MIPS_FPU_ULE;
4400 is_true = TRUE;
4401 break;
4402 default:
4403 g_assert_not_reached ();
4406 if (is_ordered) {
4407 /* Skip the check if unordered */
4408 mips_fcmpd (code, MIPS_FPU_UN, ins->sreg1, ins->sreg2);
4409 mips_nop (code);
4410 buf = (guint32*)code;
4411 mips_fbtrue (code, 0);
4412 mips_nop (code);
4415 mips_fcmpd (code, cond, ins->sreg1, ins->sreg2);
4416 mips_nop (code);
4417 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4418 if (is_true)
4419 mips_fbtrue (code, 0);
4420 else
4421 mips_fbfalse (code, 0);
4422 mips_nop (code);
4424 if (is_ordered)
4425 mips_patch (buf, (guint32)code);
4426 break;
4428 case OP_CKFINITE: {
4429 guint32 *branch_patch;
4431 mips_mfc1 (code, mips_at, ins->sreg1+1);
4432 mips_srl (code, mips_at, mips_at, 16+4);
4433 mips_andi (code, mips_at, mips_at, 2047);
4434 mips_addiu (code, mips_at, mips_at, -2047);
4436 branch_patch = (guint32 *)(void *)code;
4437 mips_bne (code, mips_at, mips_zero, 0);
4438 mips_nop (code);
4440 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
4441 mips_patch (branch_patch, (guint32)code);
4442 mips_fmovd (code, ins->dreg, ins->sreg1);
4443 break;
4445 case OP_JUMP_TABLE:
4446 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
4447 mips_load (code, ins->dreg, 0x0f0f0f0f);
4448 break;
4449 case OP_LIVERANGE_START: {
4450 if (cfg->verbose_level > 1)
4451 printf ("R%d START=0x%x\n", MONO_VARINFO (cfg, ins->inst_c0)->vreg, (int)(code - cfg->native_code));
4452 MONO_VARINFO (cfg, ins->inst_c0)->live_range_start = code - cfg->native_code;
4453 break;
4455 case OP_LIVERANGE_END: {
4456 if (cfg->verbose_level > 1)
4457 printf ("R%d END=0x%x\n", MONO_VARINFO (cfg, ins->inst_c0)->vreg, (int)(code - cfg->native_code));
4458 MONO_VARINFO (cfg, ins->inst_c0)->live_range_end = code - cfg->native_code;
4459 break;
4461 case OP_GC_SAFE_POINT:
4462 break;
4465 default:
4466 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4467 g_assert_not_reached ();
4470 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4471 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
4472 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
4473 g_assert_not_reached ();
4476 cpos += max_len;
4478 last_ins = ins;
4481 set_code_cursor (cfg, code);
4484 void
4485 mono_arch_register_lowlevel_calls (void)
4489 void
4490 mono_arch_patch_code (MonoCompile *cfg, MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors, MonoError *error)
4492 MonoJumpInfo *patch_info;
4494 error_init (error);
4496 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4497 unsigned char *ip = patch_info->ip.i + code;
4498 const unsigned char *target = NULL;
4500 switch (patch_info->type) {
4501 case MONO_PATCH_INFO_IP:
4502 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)ip);
4503 continue;
4504 case MONO_PATCH_INFO_SWITCH: {
4505 gpointer *table = (gpointer *)patch_info->data.table->table;
4506 int i;
4508 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)table);
4510 for (i = 0; i < patch_info->data.table->table_size; i++) {
4511 table [i] = (int)patch_info->data.table->table [i] + code;
4513 continue;
4515 case MONO_PATCH_INFO_METHODCONST:
4516 case MONO_PATCH_INFO_CLASS:
4517 case MONO_PATCH_INFO_IMAGE:
4518 case MONO_PATCH_INFO_FIELD:
4519 case MONO_PATCH_INFO_VTABLE:
4520 case MONO_PATCH_INFO_IID:
4521 case MONO_PATCH_INFO_SFLDA:
4522 case MONO_PATCH_INFO_LDSTR:
4523 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4524 case MONO_PATCH_INFO_LDTOKEN:
4525 case MONO_PATCH_INFO_R4:
4526 case MONO_PATCH_INFO_R8:
4527 /* from OP_AOTCONST : lui + addiu */
4528 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors, error);
4529 return_if_nok (error);
4531 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)target);
4532 continue;
4533 #if 0
4534 case MONO_PATCH_INFO_EXC_NAME:
4535 g_assert_not_reached ();
4536 *((gconstpointer *)(void *)(ip + 1)) = patch_info->data.name;
4537 continue;
4538 #endif
4539 case MONO_PATCH_INFO_NONE:
4540 /* everything is dealt with at epilog output time */
4541 continue;
4542 default:
4543 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors, error);
4544 return_if_nok (error);
4546 mips_patch ((guint32 *)(void *)ip, (guint32)target);
4547 break;
4552 void
4553 mips_adjust_stackframe(MonoCompile *cfg)
4555 MonoBasicBlock *bb;
4556 int delta, threshold, i;
4557 MonoMethodSignature *sig;
4558 int ra_offset;
4560 if (cfg->stack_offset == cfg->arch.local_alloc_offset)
4561 return;
4563 /* adjust cfg->stack_offset for account for down-spilling */
4564 cfg->stack_offset += SIZEOF_REGISTER;
4566 /* re-align cfg->stack_offset if needed (due to var spilling) */
4567 cfg->stack_offset = (cfg->stack_offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
4568 delta = cfg->stack_offset - cfg->arch.local_alloc_offset;
4569 if (cfg->verbose_level > 2) {
4570 g_print ("mips_adjust_stackframe:\n");
4571 g_print ("\tspillvars allocated 0x%x -> 0x%x\n", cfg->arch.local_alloc_offset, cfg->stack_offset);
4573 threshold = cfg->arch.local_alloc_offset;
4574 ra_offset = cfg->stack_offset - sizeof(gpointer);
4575 if (cfg->verbose_level > 2) {
4576 g_print ("\tra_offset %d/0x%x delta %d/0x%x\n", ra_offset, ra_offset, delta, delta);
4579 sig = mono_method_signature_internal (cfg->method);
4580 if (sig && sig->ret && MONO_TYPE_ISSTRUCT (sig->ret)) {
4581 cfg->vret_addr->inst_offset += delta;
4583 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4584 MonoInst *inst = cfg->args [i];
4586 inst->inst_offset += delta;
4590 * loads and stores based off the frame reg that (used to) lie
4591 * above the spill var area need to be increased by 'delta'
4592 * to make room for the spill vars.
4594 /* Need to find loads and stores to adjust that
4595 * are above where the spillvars were inserted, but
4596 * which are not the spillvar references themselves.
4598 * Idea - since all offsets from fp are positive, make
4599 * spillvar offsets negative to begin with so we can spot
4600 * them here.
4603 #if 1
4604 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4605 int ins_cnt = 0;
4606 MonoInst *ins;
4608 if (cfg->verbose_level > 2) {
4609 g_print ("BASIC BLOCK %d:\n", bb->block_num);
4611 MONO_BB_FOR_EACH_INS (bb, ins) {
4612 int adj_c0 = 0;
4613 int adj_imm = 0;
4615 if (cfg->verbose_level > 2) {
4616 mono_print_ins_index (ins_cnt, ins);
4618 /* The == mips_sp tests catch FP spills */
4619 if (MONO_IS_LOAD_MEMBASE(ins) && ((ins->inst_basereg == mips_fp) ||
4620 (ins->inst_basereg == mips_sp))) {
4621 switch (ins->opcode) {
4622 case OP_LOADI8_MEMBASE:
4623 case OP_LOADR8_MEMBASE:
4624 adj_c0 = 8;
4625 break;
4626 default:
4627 adj_c0 = 4;
4628 break;
4630 } else if (MONO_IS_STORE_MEMBASE(ins) && ((ins->dreg == mips_fp) ||
4631 (ins->dreg == mips_sp))) {
4632 switch (ins->opcode) {
4633 case OP_STOREI8_MEMBASE_REG:
4634 case OP_STORER8_MEMBASE_REG:
4635 case OP_STOREI8_MEMBASE_IMM:
4636 adj_c0 = 8;
4637 break;
4638 default:
4639 adj_c0 = 4;
4640 break;
4643 if (((ins->opcode == OP_ADD_IMM) || (ins->opcode == OP_IADD_IMM)) && (ins->sreg1 == cfg->frame_reg))
4644 adj_imm = 1;
4645 if (adj_c0) {
4646 if (ins->inst_c0 >= threshold) {
4647 ins->inst_c0 += delta;
4648 if (cfg->verbose_level > 2) {
4649 g_print ("adj");
4650 mono_print_ins_index (ins_cnt, ins);
4653 else if (ins->inst_c0 < 0) {
4654 /* Adj_c0 holds the size of the datatype. */
4655 ins->inst_c0 = - ins->inst_c0 - adj_c0;
4656 if (cfg->verbose_level > 2) {
4657 g_print ("spill");
4658 mono_print_ins_index (ins_cnt, ins);
4661 g_assert (ins->inst_c0 != ra_offset);
4663 if (adj_imm) {
4664 if (ins->inst_imm >= threshold) {
4665 ins->inst_imm += delta;
4666 if (cfg->verbose_level > 2) {
4667 g_print ("adj");
4668 mono_print_ins_index (ins_cnt, ins);
4671 g_assert (ins->inst_c0 != ra_offset);
4674 ++ins_cnt;
4677 #endif
4681 * Stack frame layout:
4683 * ------------------- sp + cfg->stack_usage + cfg->param_area
4684 * param area incoming
4685 * ------------------- sp + cfg->stack_usage + MIPS_STACK_PARAM_OFFSET
4686 * a0-a3 incoming
4687 * ------------------- sp + cfg->stack_usage
4688 * ra
4689 * ------------------- sp + cfg->stack_usage-4
4690 * spilled regs
4691 * ------------------- sp +
4692 * MonoLMF structure optional
4693 * ------------------- sp + cfg->arch.lmf_offset
4694 * saved registers s0-s8
4695 * ------------------- sp + cfg->arch.iregs_offset
4696 * locals
4697 * ------------------- sp + cfg->param_area
4698 * param area outgoing
4699 * ------------------- sp + MIPS_STACK_PARAM_OFFSET
4700 * a0-a3 outgoing
4701 * ------------------- sp
4702 * red zone
4704 guint8 *
4705 mono_arch_emit_prolog (MonoCompile *cfg)
4707 MonoMethod *method = cfg->method;
4708 MonoMethodSignature *sig;
4709 MonoInst *inst;
4710 int alloc_size, pos, i, max_offset;
4711 int alloc2_size = 0;
4712 guint8 *code;
4713 CallInfo *cinfo;
4714 guint32 iregs_to_save = 0;
4715 #if SAVE_FP_REGS
4716 guint32 fregs_to_save = 0;
4717 #endif
4718 /* lmf_offset is the offset of the LMF from our stack pointer. */
4719 guint32 lmf_offset = cfg->arch.lmf_offset;
4720 int cfa_offset = 0;
4721 MonoBasicBlock *bb;
4723 sig = mono_method_signature_internal (method);
4724 cfg->code_size = 768 + sig->param_count * 20;
4725 code = cfg->native_code = g_malloc (cfg->code_size);
4728 * compute max_offset in order to use short forward jumps.
4730 max_offset = 0;
4731 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4732 MonoInst *ins = bb->code;
4733 bb->max_offset = max_offset;
4735 MONO_BB_FOR_EACH_INS (bb, ins)
4736 max_offset += ins_get_size (ins->opcode);
4738 if (max_offset > 0xffff)
4739 cfg->arch.long_branch = TRUE;
4742 * Currently, fp points to the bottom of the frame on MIPS, unlike other platforms.
4743 * This means that we have to adjust the offsets inside instructions which reference
4744 * arguments received on the stack, since the initial offset doesn't take into
4745 * account spill slots.
4747 mips_adjust_stackframe (cfg);
4749 /* Offset between current sp and the CFA */
4750 cfa_offset = 0;
4751 mono_emit_unwind_op_def_cfa (cfg, code, mips_sp, cfa_offset);
4753 /* stack_offset should not be changed here. */
4754 alloc_size = cfg->stack_offset;
4755 cfg->stack_usage = alloc_size;
4757 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
4758 #if SAVE_FP_REGS
4759 #if 0
4760 fregs_to_save = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
4761 #else
4762 fregs_to_save = MONO_ARCH_CALLEE_SAVED_FREGS;
4763 fregs_to_save |= (fregs_to_save << 1);
4764 #endif
4765 #endif
4766 /* If the stack size is too big, save 1024 bytes to start with
4767 * so the prologue can use imm16(reg) addressing, then allocate
4768 * the rest of the frame.
4770 if (alloc_size > ((1 << 15) - 1024)) {
4771 alloc2_size = alloc_size - 1024;
4772 alloc_size = 1024;
4774 if (alloc_size) {
4775 g_assert (mips_is_imm16 (-alloc_size));
4776 mips_addiu (code, mips_sp, mips_sp, -alloc_size);
4777 cfa_offset = alloc_size;
4778 mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
4781 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
4782 int offset = alloc_size + MIPS_RET_ADDR_OFFSET;
4783 if (mips_is_imm16(offset))
4784 mips_sw (code, mips_ra, mips_sp, offset);
4785 else {
4786 g_assert_not_reached ();
4788 /* sp = cfa - cfa_offset, so sp + offset = cfa - cfa_offset + offset */
4789 mono_emit_unwind_op_offset (cfg, code, mips_ra, offset - cfa_offset);
4792 /* XXX - optimize this later to not save all regs if LMF constructed */
4793 pos = cfg->arch.iregs_offset - alloc2_size;
4795 if (iregs_to_save) {
4796 /* save used registers in own stack frame (at pos) */
4797 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
4798 if (iregs_to_save & (1 << i)) {
4799 g_assert (pos < (int)(cfg->stack_usage - sizeof(gpointer)));
4800 g_assert (mips_is_imm16(pos));
4801 MIPS_SW (code, i, mips_sp, pos);
4802 mono_emit_unwind_op_offset (cfg, code, i, pos - cfa_offset);
4803 pos += SIZEOF_REGISTER;
4808 // FIXME: Don't save registers twice if there is an LMF
4809 // s8 has to be special cased since it is overwritten with the updated value
4810 // below
4811 if (method->save_lmf) {
4812 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
4813 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[i]);
4814 g_assert (mips_is_imm16(offset));
4815 if (MIPS_LMF_IREGMASK & (1 << i))
4816 MIPS_SW (code, i, mips_sp, offset);
4820 #if SAVE_FP_REGS
4821 /* Save float registers */
4822 if (fregs_to_save) {
4823 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
4824 if (fregs_to_save & (1 << i)) {
4825 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
4826 g_assert (mips_is_imm16(pos));
4827 mips_swc1 (code, i, mips_sp, pos);
4828 pos += sizeof (gulong);
4833 if (method->save_lmf) {
4834 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
4835 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, fregs[i]);
4836 g_assert (mips_is_imm16(offset));
4837 mips_swc1 (code, i, mips_sp, offset);
4841 #endif
4842 if (cfg->frame_reg != mips_sp) {
4843 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
4844 mono_emit_unwind_op_def_cfa (cfg, code, cfg->frame_reg, cfa_offset);
4846 if (method->save_lmf) {
4847 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[cfg->frame_reg]);
4848 g_assert (mips_is_imm16(offset));
4849 MIPS_SW (code, cfg->frame_reg, mips_sp, offset);
4853 /* store runtime generic context */
4854 if (cfg->rgctx_var) {
4855 MonoInst *ins = cfg->rgctx_var;
4857 g_assert (ins->opcode == OP_REGOFFSET);
4859 g_assert (mips_is_imm16 (ins->inst_offset));
4860 mips_sw (code, MONO_ARCH_RGCTX_REG, ins->inst_basereg, ins->inst_offset);
4863 /* load arguments allocated to register from the stack */
4864 pos = 0;
4866 if (!cfg->arch.cinfo)
4867 cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
4868 cinfo = cfg->arch.cinfo;
4870 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
4871 ArgInfo *ainfo = &cinfo->ret;
4872 inst = cfg->vret_addr;
4873 if (inst->opcode == OP_REGVAR)
4874 MIPS_MOVE (code, inst->dreg, ainfo->reg);
4875 else if (mips_is_imm16 (inst->inst_offset)) {
4876 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4877 } else {
4878 mips_load_const (code, mips_at, inst->inst_offset);
4879 mips_addu (code, mips_at, mips_at, inst->inst_basereg);
4880 mips_sw (code, ainfo->reg, mips_at, 0);
4884 if (sig->call_convention == MONO_CALL_VARARG) {
4885 ArgInfo *cookie = &cinfo->sig_cookie;
4886 int offset = alloc_size + cookie->offset;
4888 /* Save the sig cookie address */
4889 g_assert (cookie->storage == ArgOnStack);
4891 g_assert (mips_is_imm16(offset));
4892 mips_addi (code, mips_at, cfg->frame_reg, offset);
4893 mips_sw (code, mips_at, cfg->frame_reg, cfg->sig_cookie - alloc2_size);
4896 /* Keep this in sync with emit_load_volatile_arguments */
4897 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4898 ArgInfo *ainfo = cinfo->args + i;
4899 inst = cfg->args [pos];
4901 if (cfg->verbose_level > 2)
4902 g_print ("Saving argument %d (type: %d)\n", i, ainfo->storage);
4903 if (inst->opcode == OP_REGVAR) {
4904 /* Argument ends up in a register */
4905 if (ainfo->storage == ArgInIReg)
4906 MIPS_MOVE (code, inst->dreg, ainfo->reg);
4907 else if (ainfo->storage == ArgInFReg) {
4908 g_assert_not_reached();
4909 #if 0
4910 ppc_fmr (code, inst->dreg, ainfo->reg);
4911 #endif
4913 else if (ainfo->storage == ArgOnStack) {
4914 int offset = cfg->stack_usage + ainfo->offset;
4915 g_assert (mips_is_imm16(offset));
4916 mips_lw (code, inst->dreg, mips_sp, offset);
4917 } else
4918 g_assert_not_reached ();
4920 if (cfg->verbose_level > 2)
4921 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
4922 } else {
4923 /* Argument ends up on the stack */
4924 if (ainfo->storage == ArgInIReg) {
4925 int basereg_offset;
4926 /* Incoming parameters should be above this frame */
4927 if (cfg->verbose_level > 2)
4928 g_print ("stack slot at %d of %d+%d\n",
4929 inst->inst_offset, alloc_size, alloc2_size);
4930 /* g_assert (inst->inst_offset >= alloc_size); */
4931 g_assert (inst->inst_basereg == cfg->frame_reg);
4932 basereg_offset = inst->inst_offset - alloc2_size;
4933 g_assert (mips_is_imm16 (basereg_offset));
4934 switch (ainfo->size) {
4935 case 1:
4936 mips_sb (code, ainfo->reg, inst->inst_basereg, basereg_offset);
4937 break;
4938 case 2:
4939 mips_sh (code, ainfo->reg, inst->inst_basereg, basereg_offset);
4940 break;
4941 case 0: /* XXX */
4942 case 4:
4943 mips_sw (code, ainfo->reg, inst->inst_basereg, basereg_offset);
4944 break;
4945 case 8:
4946 #if (SIZEOF_REGISTER == 4)
4947 mips_sw (code, ainfo->reg, inst->inst_basereg, basereg_offset + ls_word_offset);
4948 mips_sw (code, ainfo->reg + 1, inst->inst_basereg, basereg_offset + ms_word_offset);
4949 #elif (SIZEOF_REGISTER == 8)
4950 mips_sd (code, ainfo->reg, inst->inst_basereg, basereg_offset);
4951 #endif
4952 break;
4953 default:
4954 g_assert_not_reached ();
4955 break;
4957 } else if (ainfo->storage == ArgOnStack) {
4959 * Argument comes in on the stack, and ends up on the stack
4960 * 1 and 2 byte args are passed as 32-bit quantities, but used as
4961 * 8 and 16 bit quantities. Shorten them in place.
4963 g_assert (mips_is_imm16 (inst->inst_offset));
4964 switch (ainfo->size) {
4965 case 1:
4966 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
4967 mips_sb (code, mips_at, inst->inst_basereg, inst->inst_offset);
4968 break;
4969 case 2:
4970 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
4971 mips_sh (code, mips_at, inst->inst_basereg, inst->inst_offset);
4972 break;
4973 case 0: /* XXX */
4974 case 4:
4975 case 8:
4976 break;
4977 default:
4978 g_assert_not_reached ();
4980 } else if (ainfo->storage == ArgInFReg) {
4981 g_assert (mips_is_imm16 (inst->inst_offset));
4982 g_assert (mips_is_imm16 (inst->inst_offset+4));
4983 if (ainfo->size == 8) {
4984 #if _MIPS_SIM == _ABIO32
4985 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
4986 mips_swc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
4987 #elif _MIPS_SIM == _ABIN32
4988 mips_sdc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4989 #endif
4991 else if (ainfo->size == 4)
4992 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4993 else
4994 g_assert_not_reached ();
4995 } else if (ainfo->storage == ArgStructByVal) {
4996 int i;
4997 int doffset = inst->inst_offset;
4999 g_assert (mips_is_imm16 (inst->inst_offset));
5000 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (target_mgreg_t)));
5001 /* Push the argument registers into their stack slots */
5002 for (i = 0; i < ainfo->size; ++i) {
5003 g_assert (mips_is_imm16(doffset));
5004 MIPS_SW (code, ainfo->reg + i, inst->inst_basereg, doffset);
5005 doffset += SIZEOF_REGISTER;
5007 } else if (ainfo->storage == ArgStructByAddr) {
5008 g_assert (mips_is_imm16 (inst->inst_offset));
5009 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
5010 code = emit_memcpy (code, ainfo->vtsize * sizeof (target_mgreg_t), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
5011 } else
5012 g_assert_not_reached ();
5014 pos++;
5017 if (method->save_lmf) {
5018 mips_load_const (code, mips_at, MIPS_LMF_MAGIC1);
5019 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, magic));
5021 /* This can/will clobber the a0-a3 registers */
5022 mips_call (code, mips_t9, (gpointer)mono_get_lmf_addr);
5024 /* mips_v0 is the result from mono_get_lmf_addr () (MonoLMF **) */
5025 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5026 mips_sw (code, mips_v0, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5027 /* new_lmf->previous_lmf = *lmf_addr */
5028 mips_lw (code, mips_at, mips_v0, 0);
5029 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5030 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5031 /* *(lmf_addr) = sp + lmf_offset */
5032 g_assert (mips_is_imm16(lmf_offset));
5033 mips_addiu (code, mips_at, mips_sp, lmf_offset);
5034 mips_sw (code, mips_at, mips_v0, 0);
5036 /* save method info */
5037 mips_load_const (code, mips_at, method);
5038 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, method)));
5039 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, method));
5041 /* save the current IP */
5042 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5043 mips_load_const (code, mips_at, 0x01010101);
5044 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, eip));
5047 if (alloc2_size) {
5048 if (mips_is_imm16 (-alloc2_size)) {
5049 mips_addu (code, mips_sp, mips_sp, -alloc2_size);
5051 else {
5052 mips_load_const (code, mips_at, -alloc2_size);
5053 mips_addu (code, mips_sp, mips_sp, mips_at);
5055 alloc_size += alloc2_size;
5056 cfa_offset += alloc2_size;
5057 if (cfg->frame_reg != mips_sp)
5058 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
5059 else
5060 mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
5063 set_code_cursor (cfg, code);
5065 return code;
5068 guint8 *
5069 mono_arch_emit_epilog_sub (MonoCompile *cfg)
5071 guint8 *code = NULL;
5072 MonoMethod *method = cfg->method;
5073 int i;
5074 int max_epilog_size = 16 + 20*4;
5075 int alloc2_size = 0;
5076 guint32 iregs_to_restore;
5077 #if SAVE_FP_REGS
5078 guint32 fregs_to_restore;
5079 #endif
5081 if (cfg->method->save_lmf)
5082 max_epilog_size += 128;
5084 realloc_code (cfg, max_epilog_size);
5086 code = cfg->native_code + cfg->code_len;
5088 if (cfg->frame_reg != mips_sp) {
5089 MIPS_MOVE (code, mips_sp, cfg->frame_reg);
5091 /* If the stack frame is really large, deconstruct it in two steps */
5092 if (cfg->stack_usage > ((1 << 15) - 1024)) {
5093 alloc2_size = cfg->stack_usage - 1024;
5094 /* partially deconstruct the stack */
5095 mips_load_const (code, mips_at, alloc2_size);
5096 mips_addu (code, mips_sp, mips_sp, mips_at);
5098 int pos = cfg->arch.iregs_offset - alloc2_size;
5099 iregs_to_restore = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
5100 if (iregs_to_restore) {
5101 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5102 if (iregs_to_restore & (1 << i)) {
5103 g_assert (mips_is_imm16(pos));
5104 MIPS_LW (code, i, mips_sp, pos);
5105 pos += SIZEOF_REGISTER;
5110 #if SAVE_FP_REGS
5111 #if 0
5112 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
5113 #else
5114 fregs_to_restore = MONO_ARCH_CALLEE_SAVED_FREGS;
5115 fregs_to_restore |= (fregs_to_restore << 1);
5116 #endif
5117 if (fregs_to_restore) {
5118 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5119 if (fregs_to_restore & (1 << i)) {
5120 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
5121 g_assert (mips_is_imm16(pos));
5122 mips_lwc1 (code, i, mips_sp, pos);
5123 pos += FREG_SIZE
5127 #endif
5129 /* Unlink the LMF if necessary */
5130 if (method->save_lmf) {
5131 int lmf_offset = cfg->arch.lmf_offset;
5133 /* t0 = current_lmf->previous_lmf */
5134 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5135 mips_lw (code, mips_temp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5136 /* t1 = lmf_addr */
5137 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5138 mips_lw (code, mips_t1, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5139 /* (*lmf_addr) = previous_lmf */
5140 mips_sw (code, mips_temp, mips_t1, 0);
5143 #if 0
5144 /* Restore the fp */
5145 mips_lw (code, mips_fp, mips_sp, cfg->stack_usage + MIPS_FP_ADDR_OFFSET);
5146 #endif
5147 /* Restore ra */
5148 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
5149 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET));
5150 mips_lw (code, mips_ra, mips_sp, cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET);
5152 /* Restore the stack pointer */
5153 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size));
5154 mips_addiu (code, mips_sp, mips_sp, cfg->stack_usage - alloc2_size);
5156 /* Caller will emit either return or tail-call sequence */
5158 set_code_cursor (cfg, code);
5160 return (code);
5163 void
5164 mono_arch_emit_epilog (MonoCompile *cfg)
5166 guint8 *code = mono_arch_emit_epilog_sub (cfg);
5168 mips_jr (code, mips_ra);
5169 mips_nop (code);
5171 set_code_cursor (cfg, code);
5174 /* remove once throw_exception_by_name is eliminated */
5175 #if 0
5176 static int
5177 exception_id_by_name (const char *name)
5179 if (strcmp (name, "IndexOutOfRangeException") == 0)
5180 return MONO_EXC_INDEX_OUT_OF_RANGE;
5181 if (strcmp (name, "OverflowException") == 0)
5182 return MONO_EXC_OVERFLOW;
5183 if (strcmp (name, "ArithmeticException") == 0)
5184 return MONO_EXC_ARITHMETIC;
5185 if (strcmp (name, "DivideByZeroException") == 0)
5186 return MONO_EXC_DIVIDE_BY_ZERO;
5187 if (strcmp (name, "InvalidCastException") == 0)
5188 return MONO_EXC_INVALID_CAST;
5189 if (strcmp (name, "NullReferenceException") == 0)
5190 return MONO_EXC_NULL_REF;
5191 if (strcmp (name, "ArrayTypeMismatchException") == 0)
5192 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5193 if (strcmp (name, "ArgumentException") == 0)
5194 return MONO_EXC_ARGUMENT;
5195 g_error ("Unknown intrinsic exception %s\n", name);
5196 return 0;
5198 #endif
5200 void
5201 mono_arch_emit_exceptions (MonoCompile *cfg)
5203 #if 0
5204 MonoJumpInfo *patch_info;
5205 int i;
5206 guint8 *code;
5207 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
5208 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
5209 int max_epilog_size = 50;
5211 /* count the number of exception infos */
5214 * make sure we have enough space for exceptions
5215 * 24 is the simulated call to throw_exception_by_name
5217 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5218 #if 0
5219 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5220 i = exception_id_by_name (patch_info->data.target);
5221 g_assert (i < MONO_EXC_INTRINS_NUM);
5222 if (!exc_throw_found [i]) {
5223 max_epilog_size += 12;
5224 exc_throw_found [i] = TRUE;
5227 #endif
5230 code = realloc_code (cfg, max_epilog_size);
5232 /* add code to raise exceptions */
5233 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5234 switch (patch_info->type) {
5235 case MONO_PATCH_INFO_EXC: {
5236 g_assert_not_reached();
5237 break;
5239 default:
5240 /* do nothing */
5241 break;
5245 set_code_cursor (cfg, code);
5246 #endif
5249 void
5250 mono_arch_finish_init (void)
5254 void
5255 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
5257 int this_dreg = mips_a0;
5259 if (vt_reg != -1)
5260 this_dreg = mips_a1;
5262 /* add the this argument */
5263 if (this_reg != -1) {
5264 MonoInst *this_ins;
5265 MONO_INST_NEW (cfg, this_ins, OP_MOVE);
5266 this_ins->type = this_type;
5267 this_ins->sreg1 = this_reg;
5268 this_ins->dreg = mono_alloc_ireg (cfg);
5269 mono_bblock_add_inst (cfg->cbb, this_ins);
5270 mono_call_inst_add_outarg_reg (cfg, inst, this_ins->dreg, this_dreg, FALSE);
5273 if (vt_reg != -1) {
5274 MonoInst *vtarg;
5275 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
5276 vtarg->type = STACK_MP;
5277 vtarg->sreg1 = vt_reg;
5278 vtarg->dreg = mono_alloc_ireg (cfg);
5279 mono_bblock_add_inst (cfg->cbb, vtarg);
5280 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, mips_a0, FALSE);
5284 MonoInst*
5285 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5287 MonoInst *ins = NULL;
5289 return ins;
5292 MonoInst*
5293 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5295 return NULL;
5298 host_mgreg_t
5299 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5301 return ctx->sc_regs [reg];
5304 #define ENABLE_WRONG_METHOD_CHECK 0
5306 #define MIPS_LOAD_SEQUENCE_LENGTH 8
5307 #define CMP_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 4)
5308 #define BR_SIZE 8
5309 #define LOADSTORE_SIZE 4
5310 #define JUMP_IMM_SIZE 16
5311 #define JUMP_IMM32_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 8)
5312 #define LOAD_CONST_SIZE 8
5313 #define JUMP_JR_SIZE 8
5316 * LOCKING: called with the domain lock held
5318 gpointer
5319 mono_arch_build_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5320 gpointer fail_tramp)
5322 int i;
5323 int size = 0;
5324 guint8 *code, *start, *patch;
5326 for (i = 0; i < count; ++i) {
5327 MonoIMTCheckItem *item = imt_entries [i];
5329 if (item->is_equals) {
5330 if (item->check_target_idx) {
5331 item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_JR_SIZE;
5332 if (item->has_target_code)
5333 item->chunk_size += LOAD_CONST_SIZE;
5334 else
5335 item->chunk_size += LOADSTORE_SIZE;
5336 } else {
5337 if (fail_tramp) {
5338 item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_IMM32_SIZE +
5339 LOADSTORE_SIZE + JUMP_IMM32_SIZE;
5340 if (!item->has_target_code)
5341 item->chunk_size += LOADSTORE_SIZE;
5342 } else {
5343 item->chunk_size += LOADSTORE_SIZE + JUMP_JR_SIZE;
5344 #if ENABLE_WRONG_METHOD_CHECK
5345 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5346 #endif
5349 } else {
5350 item->chunk_size += CMP_SIZE + BR_SIZE;
5351 imt_entries [item->check_target_idx]->compare_done = TRUE;
5353 size += item->chunk_size;
5355 /* the initial load of the vtable address */
5356 size += MIPS_LOAD_SEQUENCE_LENGTH;
5357 if (fail_tramp) {
5358 code = mono_method_alloc_generic_virtual_trampoline (domain, size);
5359 } else {
5360 code = mono_domain_code_reserve (domain, size);
5362 start = code;
5364 /* t7 points to the vtable */
5365 mips_load_const (code, mips_t7, (gsize)(& (vtable->vtable [0])));
5367 for (i = 0; i < count; ++i) {
5368 MonoIMTCheckItem *item = imt_entries [i];
5370 item->code_target = code;
5371 if (item->is_equals) {
5372 if (item->check_target_idx) {
5373 mips_load_const (code, mips_temp, (gsize)item->key);
5374 item->jmp_code = code;
5375 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5376 mips_nop (code);
5377 if (item->has_target_code) {
5378 mips_load_const (code, mips_t9,
5379 item->value.target_code);
5381 else {
5382 mips_lw (code, mips_t9, mips_t7,
5383 (sizeof (target_mgreg_t) * item->value.vtable_slot));
5385 mips_jr (code, mips_t9);
5386 mips_nop (code);
5387 } else {
5388 if (fail_tramp) {
5389 mips_load_const (code, mips_temp, (gsize)item->key);
5390 patch = code;
5391 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5392 mips_nop (code);
5393 if (item->has_target_code) {
5394 mips_load_const (code, mips_t9,
5395 item->value.target_code);
5396 } else {
5397 g_assert (vtable);
5398 mips_load_const (code, mips_at,
5399 & (vtable->vtable [item->value.vtable_slot]));
5400 mips_lw (code, mips_t9, mips_at, 0);
5402 mips_jr (code, mips_t9);
5403 mips_nop (code);
5404 mips_patch ((guint32 *)(void *)patch, (guint32)code);
5405 mips_load_const (code, mips_t9, fail_tramp);
5406 mips_jr (code, mips_t9);
5407 mips_nop (code);
5408 } else {
5409 /* enable the commented code to assert on wrong method */
5410 #if ENABLE_WRONG_METHOD_CHECK
5411 ppc_load (code, ppc_r0, (guint32)item->key);
5412 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5413 patch = code;
5414 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5415 #endif
5416 mips_lw (code, mips_t9, mips_t7,
5417 (sizeof (target_mgreg_t) * item->value.vtable_slot));
5418 mips_jr (code, mips_t9);
5419 mips_nop (code);
5421 #if ENABLE_WRONG_METHOD_CHECK
5422 ppc_patch (patch, code);
5423 ppc_break (code);
5424 #endif
5427 } else {
5428 mips_load_const (code, mips_temp, (gulong)item->key);
5429 mips_slt (code, mips_temp, MONO_ARCH_IMT_REG, mips_temp);
5431 item->jmp_code = code;
5432 mips_beq (code, mips_temp, mips_zero, 0);
5433 mips_nop (code);
5436 /* patch the branches to get to the target items */
5437 for (i = 0; i < count; ++i) {
5438 MonoIMTCheckItem *item = imt_entries [i];
5439 if (item->jmp_code && item->check_target_idx) {
5440 mips_patch ((guint32 *)item->jmp_code,
5441 (guint32)imt_entries [item->check_target_idx]->code_target);
5445 if (!fail_tramp)
5446 UnlockedAdd (&mono_stats.imt_trampolines_size, code - start);
5447 g_assert (code - start <= size);
5448 mono_arch_flush_icache (start, size);
5449 MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_IMT_TRAMPOLINE, NULL));
5451 mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), domain);
5453 return start;
5456 MonoMethod*
5457 mono_arch_find_imt_method (host_mgreg_t *regs, guint8 *code)
5459 return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
5462 MonoVTable*
5463 mono_arch_find_static_call_vtable (host_mgreg_t *regs, guint8 *code)
5465 return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
5468 /* Soft Debug support */
5469 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
5472 * mono_arch_set_breakpoint:
5474 * See mini-amd64.c for docs.
5476 void
5477 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
5479 guint8 *code = ip;
5480 guint32 addr = (guint32)bp_trigger_page;
5482 mips_load_const (code, mips_t9, addr);
5483 mips_lw (code, mips_t9, mips_t9, 0);
5485 mono_arch_flush_icache (ip, code - ip);
5489 * mono_arch_clear_breakpoint:
5491 * See mini-amd64.c for docs.
5493 void
5494 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
5496 guint8 *code = ip;
5498 mips_nop (code);
5499 mips_nop (code);
5500 mips_nop (code);
5502 mono_arch_flush_icache (ip, code - ip);
5506 * mono_arch_start_single_stepping:
5508 * See mini-amd64.c for docs.
5510 void
5511 mono_arch_start_single_stepping (void)
5513 mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
5517 * mono_arch_stop_single_stepping:
5519 * See mini-amd64.c for docs.
5521 void
5522 mono_arch_stop_single_stepping (void)
5524 mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
5528 * mono_arch_is_single_step_event:
5530 * See mini-amd64.c for docs.
5532 gboolean
5533 mono_arch_is_single_step_event (void *info, void *sigctx)
5535 siginfo_t* sinfo = (siginfo_t*) info;
5536 /* Sometimes the address is off by 4 */
5537 if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
5538 return TRUE;
5539 else
5540 return FALSE;
5544 * mono_arch_is_breakpoint_event:
5546 * See mini-amd64.c for docs.
5548 gboolean
5549 mono_arch_is_breakpoint_event (void *info, void *sigctx)
5551 siginfo_t* sinfo = (siginfo_t*) info;
5552 /* Sometimes the address is off by 4 */
5553 if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
5554 return TRUE;
5555 else
5556 return FALSE;
5560 * mono_arch_skip_breakpoint:
5562 * See mini-amd64.c for docs.
5564 void
5565 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
5567 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
5571 * mono_arch_skip_single_step:
5573 * See mini-amd64.c for docs.
5575 void
5576 mono_arch_skip_single_step (MonoContext *ctx)
5578 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
5582 * mono_arch_get_seq_point_info:
5584 * See mini-amd64.c for docs.
5586 SeqPointInfo*
5587 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
5589 NOT_IMPLEMENTED;
5590 return NULL;
5593 #endif /* MONO_ARCH_SOFT_DEBUG_SUPPORTED */
5595 gboolean
5596 mono_arch_opcode_supported (int opcode)
5598 return FALSE;
5601 gboolean
5602 mono_arch_tailcall_supported (MonoCompile *cfg, MonoMethodSignature *caller_sig, MonoMethodSignature *callee_sig, gboolean virtual_)
5604 return FALSE;
5607 gpointer
5608 mono_arch_load_function (MonoJitICallId jit_icall_id)
5610 return NULL;