2010-04-06 Rodrigo Kumpera <rkumpera@novell.com>
[mono.git] / mono / mini / mini-mips.c
blobde827e33b96e4cf1990eee0ac3df1461e9c3e9cb
1 /*
2 * mini-mips.c: MIPS backend for the Mono code generator
4 * Authors:
5 * Mark Mason (mason@broadcom.com)
7 * Based on mini-ppc.c by
8 * Paolo Molaro (lupus@ximian.com)
9 * Dietmar Maurer (dietmar@ximian.com)
11 * (C) 2006 Broadcom
12 * (C) 2003 Ximian, Inc.
14 #include "mini.h"
15 #include <string.h>
16 #include <asm/cachectl.h>
18 #include <mono/metadata/appdomain.h>
19 #include <mono/metadata/debug-helpers.h>
21 #include <mono/arch/mips/mips-codegen.h>
23 #include "mini-mips.h"
24 #include "cpu-mips.h"
25 #include "trace.h"
26 #include "ir-emit.h"
28 #define SAVE_FP_REGS 0
29 #define SAVE_ALL_REGS 0
30 #define EXTRA_STACK_SPACE 0 /* suppresses some s-reg corruption issues */
31 #define LONG_BRANCH 1 /* needed for yyparse in mcs */
33 #define SAVE_LMF 1
34 #define ALWAYS_USE_FP 1
35 #define ALWAYS_SAVE_RA 1 /* call-handler & switch currently clobber ra */
37 #define PROMOTE_R4_TO_R8 1 /* promote single values in registers to doubles */
38 #define USE_MUL 1 /* use mul instead of mult/mflo for multiply */
40 enum {
41 TLS_MODE_DETECT,
42 TLS_MODE_FAILED,
43 TLS_MODE_LTHREADS,
44 TLS_MODE_NPTL
47 /* This mutex protects architecture specific caches */
48 #define mono_mini_arch_lock() EnterCriticalSection (&mini_arch_mutex)
49 #define mono_mini_arch_unlock() LeaveCriticalSection (&mini_arch_mutex)
50 static CRITICAL_SECTION mini_arch_mutex;
52 int mono_exc_esp_offset = 0;
53 static int tls_mode = TLS_MODE_DETECT;
54 static int lmf_pthread_key = -1;
55 static int monothread_key = -1;
56 static int monodomain_key = -1;
58 #undef DEBUG
59 #define DEBUG(a) if (cfg->verbose_level > 1) a
60 #undef DEBUG
61 #define DEBUG(a) a
62 #undef DEBUG
63 #define DEBUG(a)
65 #define EMIT_SYSTEM_EXCEPTION_NAME(exc_name) \
66 do { \
67 code = mips_emit_exc_by_name (code, exc_name); \
68 cfg->bb_exit->max_offset += 16; \
69 } while (0)
72 #define emit_linuxthreads_tls(code,dreg,key) do {\
73 int off1, off2; \
74 off1 = offsets_from_pthread_key ((key), &off2); \
75 g_assert_not_reached (); \
76 ppc_lwz ((code), (dreg), off1, ppc_r2); \
77 ppc_lwz ((code), (dreg), off2, (dreg)); \
78 } while (0);
81 #define emit_tls_access(code,dreg,key) do { \
82 switch (tls_mode) { \
83 case TLS_MODE_LTHREADS: emit_linuxthreads_tls(code,dreg,key); break; \
84 default: g_assert_not_reached (); \
85 } \
86 } while (0)
88 #define MONO_EMIT_NEW_LOAD_R8(cfg,dr,addr) do { \
89 MonoInst *inst; \
90 MONO_INST_NEW ((cfg), (inst), OP_R8CONST); \
91 inst->type = STACK_R8; \
92 inst->dreg = (dr); \
93 inst->inst_p0 = (void*)(addr); \
94 mono_bblock_add_inst (cfg->cbb, inst); \
95 } while (0)
97 #define ins_is_compare(ins) ((ins) && (((ins)->opcode == OP_COMPARE) \
98 || ((ins)->opcode == OP_ICOMPARE) \
99 || ((ins)->opcode == OP_LCOMPARE)))
100 #define ins_is_compare_imm(ins) ((ins) && (((ins)->opcode == OP_COMPARE_IMM) \
101 || ((ins)->opcode == OP_ICOMPARE_IMM) \
102 || ((ins)->opcode == OP_LCOMPARE_IMM)))
104 #define INS_REWRITE(ins, op, _s1, _s2) do { \
105 int s1 = _s1; \
106 int s2 = _s2; \
107 ins->opcode = (op); \
108 ins->sreg1 = (s1); \
109 ins->sreg2 = (s2); \
110 } while (0);
112 #define INS_REWRITE_IMM(ins, op, _s1, _imm) do { \
113 int s1 = _s1; \
114 ins->opcode = (op); \
115 ins->sreg1 = (s1); \
116 ins->inst_imm = (_imm); \
117 } while (0);
120 typedef struct InstList InstList;
122 struct InstList {
123 InstList *prev;
124 InstList *next;
125 MonoInst *data;
128 enum {
129 RegTypeGeneral,
130 RegTypeBase,
131 RegTypeFP,
132 RegTypeStructByVal,
133 RegTypeStructByAddr
136 typedef struct {
137 gint32 offset;
138 guint16 vtsize; /* in param area */
139 guint8 reg;
140 guint8 regtype : 4; /* 0 general, 1 basereg, 2 floating point register, see RegType* */
141 guint8 size : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */
142 } ArgInfo;
144 typedef struct {
145 int nargs;
146 int gr;
147 int fr;
148 gboolean gr_passed;
149 gboolean on_stack;
150 int stack_size;
151 guint32 stack_usage;
152 guint32 struct_ret;
153 ArgInfo ret;
154 ArgInfo sig_cookie;
155 ArgInfo args [1];
156 } CallInfo;
158 void patch_lui_addiu(guint32 *ip, guint32 val);
159 guint8 *mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code);
160 guint8 *mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins);
161 void mips_adjust_stackframe(MonoCompile *cfg);
162 void mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg);
163 MonoInst *mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args);
166 void
167 mono_arch_flush_icache (guint8 *code, gint size)
169 /* Linux/MIPS specific */
170 cacheflush (code, size, BCACHE);
173 void
174 mono_arch_flush_register_windows (void)
178 gboolean
179 mono_arch_is_inst_imm (gint64 imm)
181 return TRUE;
184 static guint8 *
185 mips_emit_exc_by_name(guint8 *code, const char *name)
187 guint32 addr;
188 MonoClass *exc_class;
190 exc_class = mono_class_from_name (mono_defaults.corlib, "System", name);
191 g_assert (exc_class);
193 mips_load_const (code, mips_a0, exc_class->type_token);
194 addr = (guint32) mono_arch_get_throw_corlib_exception ();
195 mips_load_const (code, mips_t9, addr);
196 mips_jalr (code, mips_t9, mips_ra);
197 mips_nop (code);
199 return code;
203 guint8 *
204 mips_emit_load_const(guint8 *code, int dreg, mgreg_t v)
206 if (mips_is_imm16 (v))
207 mips_addiu (code, dreg, mips_zero, ((guint32)v) & 0xffff);
208 else {
209 #ifdef SIZEOF_REGISTER == 8
210 if (v != (long) v) {
211 /* v is not a sign-extended 32-bit value */
212 mips_lui (code, dreg, mips_zero, (guint32)((v >> (32+16)) & 0xffff));
213 mips_ori (code, dreg, dreg, (guint32)((v >> (32)) & 0xffff));
214 mips_dsll (code, dreg, dreg, 16);
215 mips_ori (code, dreg, dreg, (guint32)((v >> (16)) & 0xffff));
216 mips_dsll (code, dreg, dreg, 16);
217 mips_ori (code, dreg, dreg, (guint32)(v & 0xffff));
218 return code;
220 #endif
221 if (((guint32)v) & (1 << 15)) {
222 mips_lui (code, dreg, mips_zero, (((guint32)v)>>16)+1);
224 else {
225 mips_lui (code, dreg, mips_zero, (((guint32)v)>>16));
227 if (((guint32)v) & 0xffff)
228 mips_addiu (code, dreg, dreg, ((guint32)v) & 0xffff);
230 return code;
233 guint8 *
234 mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins)
236 #if LONG_BRANCH
237 int br_offset = 5;
238 #endif
240 g_assert (ins);
241 #if LONG_BRANCH
242 /* Invert test and emit branch around jump */
243 switch (op) {
244 case OP_MIPS_BEQ:
245 mips_bne (code, ins->sreg1, ins->sreg2, br_offset);
246 mips_nop (code);
247 break;
248 case OP_MIPS_BNE:
249 mips_beq (code, ins->sreg1, ins->sreg2, br_offset);
250 mips_nop (code);
251 break;
252 case OP_MIPS_BGEZ:
253 mips_bltz (code, ins->sreg1, br_offset);
254 mips_nop (code);
255 break;
256 case OP_MIPS_BGTZ:
257 mips_blez (code, ins->sreg1, br_offset);
258 mips_nop (code);
259 break;
260 case OP_MIPS_BLEZ:
261 mips_bgtz (code, ins->sreg1, br_offset);
262 mips_nop (code);
263 break;
264 case OP_MIPS_BLTZ:
265 mips_bgez (code, ins->sreg1, br_offset);
266 mips_nop (code);
267 break;
268 default:
269 g_assert_not_reached ();
271 mono_add_patch_info (cfg, code - cfg->native_code,
272 MONO_PATCH_INFO_BB, ins->inst_true_bb);
273 mips_lui (code, mips_at, mips_zero, 0);
274 mips_addiu (code, mips_at, mips_at, 0);
275 mips_jr (code, mips_at);
276 mips_nop (code);
277 #else
278 mono_add_patch_info (cfg, code - cfg->native_code,
279 MONO_PATCH_INFO_BB, ins->inst_true_bb);
280 switch (op) {
281 case OP_MIPS_BEQ:
282 mips_beq (code, ins->sreg1, ins->sreg2, 0);
283 mips_nop (code);
284 break;
285 case OP_MIPS_BNE:
286 mips_bne (code, ins->sreg1, ins->sreg2, 0);
287 mips_nop (code);
288 break;
289 case OP_MIPS_BGEZ:
290 mips_bgez (code, ins->sreg1, 0);
291 mips_nop (code);
292 break;
293 case OP_MIPS_BGTZ:
294 mips_bgtz (code, ins->sreg1, 0);
295 mips_nop (code);
296 break;
297 case OP_MIPS_BLEZ:
298 mips_blez (code, ins->sreg1, 0);
299 mips_nop (code);
300 break;
301 case OP_MIPS_BLTZ:
302 mips_bltz (code, ins->sreg1, 0);
303 mips_nop (code);
304 break;
305 default:
306 g_assert_not_reached ();
308 #endif
309 return (code);
312 /* XXX - big-endian dependent? */
313 void
314 patch_lui_addiu(guint32 *ip, guint32 val)
316 guint16 *__lui_addiu = (guint16*)(void *)(ip);
318 #if 0
319 printf ("patch_lui_addiu ip=0x%08x (0x%08x, 0x%08x) to point to 0x%08x\n",
320 ip, ((guint32 *)ip)[0], ((guint32 *)ip)[1], val);
321 fflush (stdout);
322 #endif
323 if (((guint32)(val)) & (1 << 15))
324 __lui_addiu [MINI_LS_WORD_IDX] = ((((guint32)(val)) >> 16) & 0xffff) + 1;
325 else
326 __lui_addiu [MINI_LS_WORD_IDX] = (((guint32)(val)) >> 16) & 0xffff;
327 __lui_addiu [MINI_LS_WORD_IDX + 2] = ((guint32)(val)) & 0xffff;
328 mono_arch_flush_icache ((guint8 *)ip, 8);
331 guint32 trap_target;
332 void
333 mips_patch (guint32 *code, guint32 target)
335 guint32 ins = *code;
336 guint32 op = ins >> 26;
337 guint32 diff, offset;
339 g_assert (trap_target != target);
340 //printf ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
341 switch (op) {
342 case 0x00: /* jr ra */
343 if (ins == 0x3e00008)
344 break;
345 g_assert_not_reached ();
346 break;
347 case 0x02: /* j */
348 case 0x03: /* jal */
349 g_assert (!(target & 0x03));
350 g_assert ((target & 0xfc000000) == (((guint32)code) & 0xfc000000));
351 ins = (ins & 0xfc000000) | (((target) >> 2) & 0x03ffffff);
352 *code = ins;
353 mono_arch_flush_icache ((guint8 *)code, 4);
354 break;
355 case 0x01: /* BLTZ */
356 case 0x04: /* BEQ */
357 case 0x05: /* BNE */
358 case 0x06: /* BLEZ */
359 case 0x07: /* BGTZ */
360 case 0x11: /* bc1t */
361 diff = target - (guint32)(code + 1);
362 g_assert (((diff & 0x0003ffff) == diff) || ((diff | 0xfffc0000) == diff));
363 g_assert (!(diff & 0x03));
364 offset = ((gint32)diff) >> 2;
365 g_assert (((int)offset) == ((int)(short)offset));
366 ins = (ins & 0xffff0000) | (offset & 0x0000ffff);
367 *code = ins;
368 mono_arch_flush_icache ((guint8 *)code, 4);
369 break;
370 case 0x0f: /* LUI / ADDIU pair */
371 patch_lui_addiu (code, target);
372 mono_arch_flush_icache ((guint8 *)code, 8);
373 break;
375 default:
376 printf ("unknown op 0x%02x (0x%08x) @ %p\n", op, ins, code);
377 g_assert_not_reached ();
381 #if 0
382 static int
383 offsets_from_pthread_key (guint32 key, int *offset2)
385 int idx1 = key / 32;
386 int idx2 = key % 32;
387 *offset2 = idx2 * sizeof (gpointer);
388 return 284 + idx1 * sizeof (gpointer);
390 #endif
392 const char*
393 mono_arch_regname (int reg) {
394 #if _MIPS_SIM == _ABIO32
395 static const char * rnames[] = {
396 "zero", "at", "v0", "v1",
397 "a0", "a1", "a2", "a3",
398 "t0", "t1", "t2", "t3",
399 "t4", "t5", "t6", "t7",
400 "s0", "s1", "s2", "s3",
401 "s4", "s5", "s6", "s7",
402 "t8", "t9", "k0", "k1",
403 "gp", "sp", "fp", "ra"
405 #elif _MIPS_SIM == _ABIN32
406 static const char * rnames[] = {
407 "zero", "at", "v0", "v1",
408 "a0", "a1", "a2", "a3",
409 "a4", "a5", "a6", "a7",
410 "t0", "t1", "t2", "t3",
411 "s0", "s1", "s2", "s3",
412 "s4", "s5", "s6", "s7",
413 "t8", "t9", "k0", "k1",
414 "gp", "sp", "fp", "ra"
416 #endif
417 if (reg >= 0 && reg < 32)
418 return rnames [reg];
419 return "unknown";
422 const char*
423 mono_arch_fregname (int reg) {
424 static const char * rnames[] = {
425 "f0", "f1", "f2", "f3",
426 "f4", "f5", "f6", "f7",
427 "f8", "f9", "f10", "f11",
428 "f12", "f13", "f14", "f15",
429 "f16", "f17", "f18", "f19",
430 "f20", "f21", "f22", "f23",
431 "f24", "f25", "f26", "f27",
432 "f28", "f29", "f30", "f31"
434 if (reg >= 0 && reg < 32)
435 return rnames [reg];
436 return "unknown";
439 /* this function overwrites at */
440 static guint8*
441 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
443 /* XXX write a loop, not an unrolled loop */
444 while (size > 0) {
445 mips_lw (code, mips_at, sreg, soffset);
446 mips_sw (code, mips_at, dreg, doffset);
447 size -= 4;
448 soffset += 4;
449 doffset += 4;
451 return code;
455 * mono_arch_get_argument_info:
456 * @csig: a method signature
457 * @param_count: the number of parameters to consider
458 * @arg_info: an array to store the result infos
460 * Gathers information on parameters such as size, alignment and
461 * padding. arg_info should be large enought to hold param_count + 1 entries.
463 * Returns the size of the activation frame.
466 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
468 int k, frame_size = 0;
469 guint32 size, align, pad;
470 int offset = 0;
472 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
473 frame_size += sizeof (gpointer);
474 offset += 4;
477 arg_info [0].offset = offset;
479 if (csig->hasthis) {
480 frame_size += sizeof (gpointer);
481 offset += 4;
484 arg_info [0].size = frame_size;
486 for (k = 0; k < param_count; k++) {
487 size = mini_type_stack_size_full (NULL, csig->params [k], &align, csig->pinvoke);
489 /* ignore alignment for now */
490 align = 1;
492 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
493 arg_info [k].pad = pad;
494 frame_size += size;
495 arg_info [k + 1].pad = 0;
496 arg_info [k + 1].size = size;
497 offset += pad;
498 arg_info [k + 1].offset = offset;
499 offset += size;
502 align = MONO_ARCH_FRAME_ALIGNMENT;
503 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
504 arg_info [k].pad = pad;
506 return frame_size;
510 gpointer
511 mono_arch_get_this_arg_from_call (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, mgreg_t *regs, guint8 *code)
513 /* FIXME: handle returning a struct */
514 if (MONO_TYPE_ISSTRUCT (sig->ret))
515 return (gpointer)regs [mips_a1];
516 return (gpointer)regs [mips_a0];
520 * Initialize the cpu to execute managed code.
522 void
523 mono_arch_cpu_init (void)
528 * Initialize architecture specific code.
530 void
531 mono_arch_init (void)
533 InitializeCriticalSection (&mini_arch_mutex);
537 * Cleanup architecture specific code.
539 void
540 mono_arch_cleanup (void)
542 DeleteCriticalSection (&mini_arch_mutex);
546 * This function returns the optimizations supported on this cpu.
548 guint32
549 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
551 guint32 opts = 0;
553 /* no mips-specific optimizations yet */
554 *exclude_mask = 0;
555 return opts;
558 static gboolean
559 is_regsize_var (MonoType *t) {
560 if (t->byref)
561 return TRUE;
562 t = mono_type_get_underlying_type (t);
563 switch (t->type) {
564 case MONO_TYPE_I4:
565 case MONO_TYPE_U4:
566 #if (SIZEOF_REGISTER == 8)
567 case MONO_TYPE_I8:
568 case MONO_TYPE_U8:
569 #endif
570 case MONO_TYPE_I:
571 case MONO_TYPE_U:
572 case MONO_TYPE_PTR:
573 case MONO_TYPE_FNPTR:
574 return TRUE;
575 case MONO_TYPE_OBJECT:
576 case MONO_TYPE_STRING:
577 case MONO_TYPE_CLASS:
578 case MONO_TYPE_SZARRAY:
579 case MONO_TYPE_ARRAY:
580 return TRUE;
581 case MONO_TYPE_GENERICINST:
582 if (!mono_type_generic_inst_is_valuetype (t))
583 return TRUE;
584 return FALSE;
585 case MONO_TYPE_VALUETYPE:
586 return FALSE;
588 return FALSE;
591 GList *
592 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
594 GList *vars = NULL;
595 int i;
597 for (i = 0; i < cfg->num_varinfo; i++) {
598 MonoInst *ins = cfg->varinfo [i];
599 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
601 /* unused vars */
602 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
603 continue;
605 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
606 continue;
608 /* we can only allocate 32 bit values */
609 if (is_regsize_var (ins->inst_vtype)) {
610 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
611 g_assert (i == vmv->idx);
612 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
616 return vars;
619 GList *
620 mono_arch_get_global_int_regs (MonoCompile *cfg)
622 GList *regs = NULL;
624 regs = g_list_prepend (regs, (gpointer)mips_s0);
625 regs = g_list_prepend (regs, (gpointer)mips_s1);
626 regs = g_list_prepend (regs, (gpointer)mips_s2);
627 regs = g_list_prepend (regs, (gpointer)mips_s3);
628 regs = g_list_prepend (regs, (gpointer)mips_s4);
629 //regs = g_list_prepend (regs, (gpointer)mips_s5);
630 regs = g_list_prepend (regs, (gpointer)mips_s6);
631 regs = g_list_prepend (regs, (gpointer)mips_s7);
633 return regs;
637 * mono_arch_regalloc_cost:
639 * Return the cost, in number of memory references, of the action of
640 * allocating the variable VMV into a register during global register
641 * allocation.
643 guint32
644 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
646 /* FIXME: */
647 return 2;
650 static void
651 args_onto_stack (CallInfo *info)
653 g_assert (!info->on_stack);
654 g_assert (info->stack_size <= MIPS_STACK_PARAM_OFFSET);
655 info->on_stack = TRUE;
656 info->stack_size = MIPS_STACK_PARAM_OFFSET;
659 #if _MIPS_SIM == _ABIO32
661 * O32 calling convention version
664 static void
665 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
666 /* First, see if we need to drop onto the stack */
667 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
668 args_onto_stack (info);
670 /* Now, place the argument */
671 if (info->on_stack) {
672 ainfo->regtype = RegTypeBase;
673 ainfo->reg = mips_sp; /* in the caller */
674 ainfo->offset = info->stack_size;
676 else {
677 ainfo->regtype = RegTypeGeneral;
678 ainfo->reg = info->gr;
679 info->gr += 1;
680 info->gr_passed = TRUE;
682 info->stack_size += 4;
685 static void
686 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
687 /* First, see if we need to drop onto the stack */
688 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
689 args_onto_stack (info);
691 /* Now, place the argument */
692 if (info->on_stack) {
693 g_assert (info->stack_size % 4 == 0);
694 info->stack_size += (info->stack_size % 8);
696 ainfo->regtype = RegTypeBase;
697 ainfo->reg = mips_sp; /* in the caller */
698 ainfo->offset = info->stack_size;
700 else {
701 // info->gr must be a0 or a2
702 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
703 g_assert(info->gr <= MIPS_LAST_ARG_REG);
705 ainfo->regtype = RegTypeGeneral;
706 ainfo->reg = info->gr;
707 info->gr += 2;
708 info->gr_passed = TRUE;
710 info->stack_size += 8;
713 static void
714 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
715 /* First, see if we need to drop onto the stack */
716 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
717 args_onto_stack (info);
719 /* Now, place the argument */
720 if (info->on_stack) {
721 ainfo->regtype = RegTypeBase;
722 ainfo->reg = mips_sp; /* in the caller */
723 ainfo->offset = info->stack_size;
725 else {
726 /* Only use FP regs for args if no int args passed yet */
727 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
728 ainfo->regtype = RegTypeFP;
729 ainfo->reg = info->fr;
730 /* Even though it's a single-precision float, it takes up two FP regs */
731 info->fr += 2;
732 /* FP and GP slots do not overlap */
733 info->gr += 1;
735 else {
736 /* Passing single-precision float arg in a GP register
737 * such as: func (0, 1.0, 2, 3);
738 * In this case, only one 'gr' register is consumed.
740 ainfo->regtype = RegTypeGeneral;
741 ainfo->reg = info->gr;
743 info->gr += 1;
744 info->gr_passed = TRUE;
747 info->stack_size += 4;
750 static void
751 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
752 /* First, see if we need to drop onto the stack */
753 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
754 args_onto_stack (info);
756 /* Now, place the argument */
757 if (info->on_stack) {
758 g_assert(info->stack_size % 4 == 0);
759 info->stack_size += (info->stack_size % 8);
761 ainfo->regtype = RegTypeBase;
762 ainfo->reg = mips_sp; /* in the caller */
763 ainfo->offset = info->stack_size;
765 else {
766 /* Only use FP regs for args if no int args passed yet */
767 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
768 ainfo->regtype = RegTypeFP;
769 ainfo->reg = info->fr;
770 info->fr += 2;
771 /* FP and GP slots do not overlap */
772 info->gr += 2;
774 else {
775 // info->gr must be a0 or a2
776 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
777 g_assert(info->gr <= MIPS_LAST_ARG_REG);
779 ainfo->regtype = RegTypeGeneral;
780 ainfo->reg = info->gr;
781 info->gr += 2;
782 info->gr_passed = TRUE;
785 info->stack_size += 8;
787 #elif _MIPS_SIM == _ABIN32
789 * N32 calling convention version
792 static void
793 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
794 /* First, see if we need to drop onto the stack */
795 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
796 args_onto_stack (info);
798 /* Now, place the argument */
799 if (info->on_stack) {
800 ainfo->regtype = RegTypeBase;
801 ainfo->reg = mips_sp; /* in the caller */
802 ainfo->offset = info->stack_size;
803 info->stack_size += SIZEOF_REGISTER;
805 else {
806 ainfo->regtype = RegTypeGeneral;
807 ainfo->reg = info->gr;
808 info->gr += 1;
809 info->gr_passed = TRUE;
813 static void
814 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
815 /* First, see if we need to drop onto the stack */
816 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
817 args_onto_stack (info);
819 /* Now, place the argument */
820 if (info->on_stack) {
821 g_assert (info->stack_size % 4 == 0);
822 info->stack_size += (info->stack_size % 8);
824 ainfo->regtype = RegTypeBase;
825 ainfo->reg = mips_sp; /* in the caller */
826 ainfo->offset = info->stack_size;
827 info->stack_size += SIZEOF_REGISTER;
829 else {
830 g_assert (info->gr <= MIPS_LAST_ARG_REG);
832 ainfo->regtype = RegTypeGeneral;
833 ainfo->reg = info->gr;
834 info->gr += 1;
835 info->gr_passed = TRUE;
839 static void
840 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
841 /* First, see if we need to drop onto the stack */
842 if (!info->on_stack) {
843 if (info->gr > MIPS_LAST_ARG_REG)
844 args_onto_stack (info);
845 else if (info->fr > MIPS_LAST_FPARG_REG)
846 args_onto_stack (info);
849 /* Now, place the argument */
850 if (info->on_stack) {
851 ainfo->regtype = RegTypeBase;
852 ainfo->reg = mips_sp; /* in the caller */
853 ainfo->offset = info->stack_size;
854 info->stack_size += FREG_SIZE;
856 else {
857 ainfo->regtype = RegTypeFP;
858 ainfo->reg = info->fr;
859 info->fr += 1;
860 /* FP and GP slots do not overlap */
861 info->gr += 1;
865 static void
866 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
867 /* First, see if we need to drop onto the stack */
868 if (!info->on_stack) {
869 if (info->gr > MIPS_LAST_ARG_REG)
870 args_onto_stack (info);
871 else if (info->fr > MIPS_LAST_FPARG_REG)
872 args_onto_stack (info);
875 /* Now, place the argument */
876 if (info->on_stack) {
877 g_assert(info->stack_size % 4 == 0);
878 info->stack_size += (info->stack_size % 8);
880 ainfo->regtype = RegTypeBase;
881 ainfo->reg = mips_sp; /* in the caller */
882 ainfo->offset = info->stack_size;
883 info->stack_size += FREG_SIZE;
885 else {
886 ainfo->regtype = RegTypeFP;
887 ainfo->reg = info->fr;
888 info->fr += 1;
889 /* FP and GP slots do not overlap */
890 info->gr += 1;
893 #endif
895 static CallInfo*
896 calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
898 guint i;
899 int n = sig->hasthis + sig->param_count;
900 MonoType* simpletype;
901 CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * n);
903 cinfo->fr = MIPS_FIRST_FPARG_REG;
904 cinfo->gr = MIPS_FIRST_ARG_REG;
905 cinfo->stack_size = 0;
907 DEBUG(printf("calculate_sizes\n"));
909 /* handle returning a struct */
910 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
911 cinfo->struct_ret = cinfo->gr;
912 add_int32_arg (cinfo, &cinfo->ret);
915 n = 0;
916 if (sig->hasthis) {
917 add_int32_arg (cinfo, cinfo->args + n);
918 n++;
920 DEBUG(printf("params: %d\n", sig->param_count));
921 for (i = 0; i < sig->param_count; ++i) {
922 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
923 /* Prevent implicit arguments and sig_cookie from
924 being passed in registers */
925 args_onto_stack (cinfo);
926 /* Emit the signature cookie just before the implicit arguments */
927 add_int32_arg (cinfo, &cinfo->sig_cookie);
929 DEBUG(printf("param %d: ", i));
930 if (sig->params [i]->byref) {
931 DEBUG(printf("byref\n"));
932 add_int32_arg (cinfo, &cinfo->args[n]);
933 n++;
934 continue;
936 simpletype = mono_type_get_underlying_type (sig->params [i]);
937 switch (simpletype->type) {
938 case MONO_TYPE_BOOLEAN:
939 case MONO_TYPE_I1:
940 case MONO_TYPE_U1:
941 DEBUG(printf("1 byte\n"));
942 cinfo->args [n].size = 1;
943 add_int32_arg (cinfo, &cinfo->args[n]);
944 n++;
945 break;
946 case MONO_TYPE_CHAR:
947 case MONO_TYPE_I2:
948 case MONO_TYPE_U2:
949 DEBUG(printf("2 bytes\n"));
950 cinfo->args [n].size = 2;
951 add_int32_arg (cinfo, &cinfo->args[n]);
952 n++;
953 break;
954 case MONO_TYPE_I4:
955 case MONO_TYPE_U4:
956 DEBUG(printf("4 bytes\n"));
957 cinfo->args [n].size = 4;
958 add_int32_arg (cinfo, &cinfo->args[n]);
959 n++;
960 break;
961 case MONO_TYPE_I:
962 case MONO_TYPE_U:
963 case MONO_TYPE_PTR:
964 case MONO_TYPE_FNPTR:
965 case MONO_TYPE_CLASS:
966 case MONO_TYPE_OBJECT:
967 case MONO_TYPE_STRING:
968 case MONO_TYPE_SZARRAY:
969 case MONO_TYPE_ARRAY:
970 cinfo->args [n].size = sizeof (gpointer);
971 add_int32_arg (cinfo, &cinfo->args[n]);
972 n++;
973 break;
974 case MONO_TYPE_GENERICINST:
975 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
976 cinfo->args [n].size = sizeof (gpointer);
977 add_int32_arg (cinfo, &cinfo->args[n]);
978 n++;
979 break;
981 /* Fall through */
982 case MONO_TYPE_VALUETYPE: {
983 int j;
984 int nwords = 0;
985 int has_offset = FALSE;
986 ArgInfo dummy_arg;
987 gint size, alignment;
988 MonoClass *klass;
990 klass = mono_class_from_mono_type (sig->params [i]);
991 if (is_pinvoke)
992 size = mono_class_native_size (klass, NULL);
993 else
994 size = mono_class_value_size (klass, NULL);
995 alignment = mono_class_min_align (klass);
996 #if MIPS_PASS_STRUCTS_BY_VALUE
997 /* Need to do alignment if struct contains long or double */
998 if (alignment > 4) {
999 if (cinfo->stack_size & (alignment - 1)) {
1000 add_int32_arg (cinfo, &dummy_arg);
1002 g_assert (!(cinfo->stack_size & (alignment - 1)));
1005 #if 0
1006 g_printf ("valuetype struct size=%d offset=%d align=%d\n",
1007 mono_class_native_size (sig->params [i]->data.klass, NULL),
1008 cinfo->stack_size, alignment);
1009 #endif
1010 nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
1011 g_assert (cinfo->args [n].size == 0);
1012 g_assert (cinfo->args [n].vtsize == 0);
1013 for (j = 0; j < nwords; ++j) {
1014 if (j == 0) {
1015 add_int32_arg (cinfo, &cinfo->args [n]);
1016 if (cinfo->on_stack)
1017 has_offset = TRUE;
1018 } else {
1019 add_int32_arg (cinfo, &dummy_arg);
1020 if (!has_offset && cinfo->on_stack) {
1021 cinfo->args [n].offset = dummy_arg.offset;
1022 has_offset = TRUE;
1025 if (cinfo->on_stack)
1026 cinfo->args [n].vtsize += 1;
1027 else
1028 cinfo->args [n].size += 1;
1030 //g_printf ("\tstack_size=%d vtsize=%d\n", cinfo->args [n].size, cinfo->args[n].vtsize);
1031 cinfo->args [n].regtype = RegTypeStructByVal;
1032 #else
1033 add_int32_arg (cinfo, &cinfo->args[n]);
1034 cinfo->args [n].regtype = RegTypeStructByAddr;
1035 #endif
1036 n++;
1037 break;
1039 case MONO_TYPE_TYPEDBYREF: {
1040 /* keep in sync or merge with the valuetype case */
1041 #if MIPS_PASS_STRUCTS_BY_VALUE
1043 int size = sizeof (MonoTypedRef);
1044 int nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
1045 cinfo->args [n].regtype = RegTypeStructByVal;
1046 if (!cinfo->on_stack && cinfo->gr <= MIPS_LAST_ARG_REG) {
1047 int rest = MIPS_LAST_ARG_REG - cinfo->gr + 1;
1048 int n_in_regs = rest >= nwords? nwords: rest;
1049 cinfo->args [n].size = n_in_regs;
1050 cinfo->args [n].vtsize = nwords - n_in_regs;
1051 cinfo->args [n].reg = cinfo->gr;
1052 cinfo->gr += n_in_regs;
1053 cinfo->gr_passed = TRUE;
1054 } else {
1055 cinfo->args [n].size = 0;
1056 cinfo->args [n].vtsize = nwords;
1058 if (cinfo->args [n].vtsize > 0) {
1059 if (!cinfo->on_stack)
1060 args_onto_stack (cinfo);
1061 g_assert(cinfo->on_stack);
1062 cinfo->args [n].offset = cinfo->stack_size;
1063 g_print ("offset for arg %d at %d\n", n, cinfo->args [n].offset);
1064 cinfo->stack_size += cinfo->args [n].vtsize * sizeof (gpointer);
1067 #else
1068 add_int32_arg (cinfo, &cinfo->args[n]);
1069 cinfo->args [n].regtype = RegTypeStructByAddr;
1070 #endif
1071 n++;
1072 break;
1074 case MONO_TYPE_U8:
1075 case MONO_TYPE_I8:
1076 DEBUG(printf("8 bytes\n"));
1077 cinfo->args [n].size = 8;
1078 add_int64_arg (cinfo, &cinfo->args[n]);
1079 n++;
1080 break;
1081 case MONO_TYPE_R4:
1082 DEBUG(printf("R4\n"));
1083 cinfo->args [n].size = 4;
1084 add_float32_arg (cinfo, &cinfo->args[n]);
1085 n++;
1086 break;
1087 case MONO_TYPE_R8:
1088 DEBUG(printf("R8\n"));
1089 cinfo->args [n].size = 8;
1090 add_float64_arg (cinfo, &cinfo->args[n]);
1091 n++;
1092 break;
1093 default:
1094 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
1099 simpletype = mono_type_get_underlying_type (sig->ret);
1100 switch (simpletype->type) {
1101 case MONO_TYPE_BOOLEAN:
1102 case MONO_TYPE_I1:
1103 case MONO_TYPE_U1:
1104 case MONO_TYPE_I2:
1105 case MONO_TYPE_U2:
1106 case MONO_TYPE_CHAR:
1107 case MONO_TYPE_I4:
1108 case MONO_TYPE_U4:
1109 case MONO_TYPE_I:
1110 case MONO_TYPE_U:
1111 case MONO_TYPE_PTR:
1112 case MONO_TYPE_FNPTR:
1113 case MONO_TYPE_CLASS:
1114 case MONO_TYPE_OBJECT:
1115 case MONO_TYPE_SZARRAY:
1116 case MONO_TYPE_ARRAY:
1117 case MONO_TYPE_STRING:
1118 cinfo->ret.reg = mips_v0;
1119 break;
1120 case MONO_TYPE_U8:
1121 case MONO_TYPE_I8:
1122 cinfo->ret.reg = mips_v0;
1123 break;
1124 case MONO_TYPE_R4:
1125 case MONO_TYPE_R8:
1126 cinfo->ret.reg = mips_f0;
1127 cinfo->ret.regtype = RegTypeFP;
1128 break;
1129 case MONO_TYPE_GENERICINST:
1130 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1131 cinfo->ret.reg = mips_v0;
1132 break;
1134 break;
1135 case MONO_TYPE_VALUETYPE:
1136 break;
1137 case MONO_TYPE_TYPEDBYREF:
1138 case MONO_TYPE_VOID:
1139 break;
1140 default:
1141 g_error ("Can't handle as return value 0x%x", sig->ret->type);
1145 /* align stack size to 16 */
1146 cinfo->stack_size = (cinfo->stack_size + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1148 cinfo->stack_usage = cinfo->stack_size;
1149 return cinfo;
1154 * Set var information according to the calling convention. mips version.
1155 * The locals var stuff should most likely be split in another method.
1157 void
1158 mono_arch_allocate_vars (MonoCompile *cfg)
1160 MonoMethodSignature *sig;
1161 MonoMethodHeader *header;
1162 MonoInst *inst;
1163 int i, offset, size, align, curinst;
1164 int frame_reg = mips_sp;
1165 guint32 iregs_to_save = 0;
1166 #if SAVE_FP_REGS
1167 guint32 fregs_to_restore;
1168 #endif
1170 /* spill down, we'll fix it in a separate pass */
1171 // cfg->flags |= MONO_CFG_HAS_SPILLUP;
1173 /* allow room for the vararg method args: void* and long/double */
1174 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1175 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1177 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1178 * call convs needs to be handled this way.
1180 if (cfg->flags & MONO_CFG_HAS_VARARGS)
1181 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1183 /* gtk-sharp and other broken code will dllimport vararg functions even with
1184 * non-varargs signatures. Since there is little hope people will get this right
1185 * we assume they won't.
1187 if (cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1188 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1190 /* a0-a3 always present */
1191 cfg->param_area = MAX (cfg->param_area, MIPS_STACK_PARAM_OFFSET);
1193 header = cfg->header;
1195 sig = mono_method_signature (cfg->method);
1198 * We use the frame register also for any method that has
1199 * exception clauses. This way, when the handlers are called,
1200 * the code will reference local variables using the frame reg instead of
1201 * the stack pointer: if we had to restore the stack pointer, we'd
1202 * corrupt the method frames that are already on the stack (since
1203 * filters get called before stack unwinding happens) when the filter
1204 * code would call any method (this also applies to finally etc.).
1207 if ((cfg->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses || ALWAYS_USE_FP)
1208 frame_reg = mips_fp;
1209 cfg->frame_reg = frame_reg;
1210 if (frame_reg != mips_sp) {
1211 cfg->used_int_regs |= 1 << frame_reg;
1214 offset = 0;
1215 curinst = 0;
1216 if (!MONO_TYPE_ISSTRUCT (sig->ret)) {
1217 /* FIXME: handle long and FP values */
1218 switch (mono_type_get_underlying_type (sig->ret)->type) {
1219 case MONO_TYPE_VOID:
1220 break;
1221 case MONO_TYPE_R4:
1222 case MONO_TYPE_R8:
1223 cfg->ret->opcode = OP_REGVAR;
1224 cfg->ret->inst_c0 = cfg->ret->dreg = mips_f0;
1225 break;
1226 default:
1227 cfg->ret->opcode = OP_REGVAR;
1228 cfg->ret->inst_c0 = mips_v0;
1229 break;
1232 /* Space for outgoing parameters, including a0-a3 */
1233 offset += cfg->param_area;
1235 /* allow room to save the return value (if it's a struct) */
1236 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1237 offset += 8;
1239 if (sig->call_convention == MONO_CALL_VARARG) {
1240 cfg->sig_cookie = MIPS_STACK_PARAM_OFFSET;
1243 /* Now handle the local variables */
1245 curinst = cfg->locals_start;
1246 for (i = curinst; i < cfg->num_varinfo; ++i) {
1247 inst = cfg->varinfo [i];
1248 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
1249 continue;
1251 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
1252 * pinvoke wrappers when they call functions returning structure
1254 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
1255 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), &align);
1256 else
1257 size = mono_type_size (inst->inst_vtype, &align);
1259 offset += align - 1;
1260 offset &= ~(align - 1);
1261 inst->inst_offset = offset;
1262 inst->opcode = OP_REGOFFSET;
1263 inst->inst_basereg = frame_reg;
1264 offset += size;
1265 // g_print ("allocating local %d to %d\n", i, inst->inst_offset);
1268 /* Space for LMF (if needed) */
1269 #if SAVE_LMF
1270 if (cfg->method->save_lmf) {
1271 /* align the offset to 16 bytes */
1272 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1273 cfg->arch.lmf_offset = offset;
1274 offset += sizeof (MonoLMF);
1276 #endif
1278 /* XXX - Saved S-regs seem to be getting clobbered by some calls with struct
1279 * args or return vals. Extra stack space avoids this in a lot of cases.
1281 offset += EXTRA_STACK_SPACE;
1283 /* Space for saved registers */
1284 cfg->arch.iregs_offset = offset;
1285 #if SAVE_ALL_REGS
1286 iregs_to_save = MONO_ARCH_CALLEE_SAVED_REGS;
1287 #else
1288 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
1289 #endif
1290 if (iregs_to_save) {
1291 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
1292 if (iregs_to_save & (1 << i)) {
1293 offset += SIZEOF_REGISTER;
1298 /* XXX - Saved S-regs seem to be getting clobbered by some calls with struct
1299 * args or return vals. Extra stack space avoids this in a lot of cases.
1301 offset += EXTRA_STACK_SPACE;
1303 /* saved float registers */
1304 #if SAVE_FP_REGS
1305 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
1306 if (fregs_to_restore) {
1307 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
1308 if (fregs_to_restore & (1 << i)) {
1309 offset += sizeof(double);
1313 #endif
1315 #if _MIPS_SIM == _ABIO32
1316 /* Now add space for saving the ra */
1317 offset += SIZEOF_VOID_P;
1319 /* change sign? */
1320 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1321 cfg->stack_offset = offset;
1322 cfg->arch.local_alloc_offset = cfg->stack_offset;
1323 #endif
1326 * Now allocate stack slots for the int arg regs (a0 - a3)
1327 * On MIPS o32, these are just above the incoming stack pointer
1328 * Even if the arg has been assigned to a regvar, it gets a stack slot
1331 /* Return struct-by-value results in a hidden first argument */
1332 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1333 cfg->vret_addr->opcode = OP_REGOFFSET;
1334 cfg->vret_addr->inst_c0 = mips_a0;
1335 cfg->vret_addr->inst_offset = offset;
1336 cfg->vret_addr->inst_basereg = frame_reg;
1337 offset += SIZEOF_REGISTER;
1340 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
1341 inst = cfg->args [i];
1342 if (inst->opcode != OP_REGVAR) {
1343 MonoType *arg_type;
1345 if (sig->hasthis && (i == 0))
1346 arg_type = &mono_defaults.object_class->byval_arg;
1347 else
1348 arg_type = sig->params [i - sig->hasthis];
1350 inst->opcode = OP_REGOFFSET;
1351 size = mono_type_size (arg_type, &align);
1353 if (size < SIZEOF_REGISTER) {
1354 size = SIZEOF_REGISTER;
1355 align = SIZEOF_REGISTER;
1357 inst->inst_basereg = frame_reg;
1358 offset = (offset + align - 1) & ~(align - 1);
1359 inst->inst_offset = offset;
1360 offset += size;
1361 if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos))
1362 cfg->sig_cookie += size;
1363 // g_print ("allocating param %d to %d\n", i, inst->inst_offset);
1365 else {
1366 #if _MIPS_SIM == _ABIO32
1367 /* o32: Even a0-a3 get stack slots */
1368 size = SIZEOF_REGISTER;
1369 align = SIZEOF_REGISTER;
1370 inst->inst_basereg = frame_reg;
1371 offset = (offset + align - 1) & ~(align - 1);
1372 inst->inst_offset = offset;
1373 offset += size;
1374 if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos))
1375 cfg->sig_cookie += size;
1376 // g_print ("allocating param %d to %d\n", i, inst->inst_offset);
1377 #endif
1380 #if _MIPS_SIM == _ABIN32
1381 /* Now add space for saving the ra */
1382 offset += SIZEOF_VOID_P;
1384 /* change sign? */
1385 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1386 cfg->stack_offset = offset;
1387 cfg->arch.local_alloc_offset = cfg->stack_offset;
1388 #endif
1391 void
1392 mono_arch_create_vars (MonoCompile *cfg)
1394 MonoMethodSignature *sig;
1396 sig = mono_method_signature (cfg->method);
1398 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1399 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1400 if (G_UNLIKELY (cfg->verbose_level > 1)) {
1401 printf ("vret_addr = ");
1402 mono_print_ins (cfg->vret_addr);
1407 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1408 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1412 * take the arguments and generate the arch-specific
1413 * instructions to properly call the function in call.
1414 * This includes pushing, moving arguments to the right register
1415 * etc.
1416 * Issue: who does the spilling if needed, and when?
1418 static void
1419 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1421 int sig_reg = mono_alloc_ireg (cfg);
1423 MONO_EMIT_NEW_ICONST (cfg, sig_reg, (guint32)call->signature);
1424 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG,
1425 mips_sp, cinfo->sig_cookie.offset, sig_reg);
1428 void
1429 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1431 MonoInst *in, *ins;
1432 MonoMethodSignature *sig;
1433 int i, n;
1434 CallInfo *cinfo;
1435 int is_virtual = 0;
1437 sig = call->signature;
1438 n = sig->param_count + sig->hasthis;
1440 cinfo = calculate_sizes (sig, sig->pinvoke);
1441 if (cinfo->struct_ret)
1442 call->used_iregs |= 1 << cinfo->struct_ret;
1444 for (i = 0; i < n; ++i) {
1445 ArgInfo *ainfo = cinfo->args + i;
1446 MonoType *t;
1448 if (i >= sig->hasthis)
1449 t = sig->params [i - sig->hasthis];
1450 else
1451 t = &mono_defaults.int_class->byval_arg;
1452 t = mini_type_get_underlying_type (cfg->generic_sharing_context, t);
1454 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos))
1455 emit_sig_cookie (cfg, call, cinfo);
1456 if (is_virtual && i == 0) {
1457 /* the argument will be attached to the call instrucion */
1458 in = call->args [i];
1459 call->used_iregs |= 1 << ainfo->reg;
1460 continue;
1462 in = call->args [i];
1463 if (ainfo->regtype == RegTypeGeneral) {
1464 #if SIZEOF_REGISTER == 4
1465 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1466 MONO_INST_NEW (cfg, ins, OP_MOVE);
1467 ins->dreg = mono_alloc_ireg (cfg);
1468 ins->sreg1 = in->dreg + 1;
1469 MONO_ADD_INS (cfg->cbb, ins);
1470 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + 1, FALSE);
1472 MONO_INST_NEW (cfg, ins, OP_MOVE);
1473 ins->dreg = mono_alloc_ireg (cfg);
1474 ins->sreg1 = in->dreg + 2;
1475 MONO_ADD_INS (cfg->cbb, ins);
1476 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1477 } else
1478 #endif
1479 if (!t->byref && (t->type == MONO_TYPE_R4)) {
1480 int freg;
1482 #if PROMOTE_R4_TO_R8
1483 /* ??? - convert to single first? */
1484 MONO_INST_NEW (cfg, ins, OP_MIPS_CVTSD);
1485 ins->dreg = mono_alloc_freg (cfg);
1486 ins->sreg1 = in->dreg;
1487 MONO_ADD_INS (cfg->cbb, ins);
1488 freg = ins->dreg;
1489 #else
1490 freg = in->dreg;
1491 #endif
1492 /* trying to load float value into int registers */
1493 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1S);
1494 ins->dreg = mono_alloc_ireg (cfg);
1495 ins->sreg1 = freg;
1496 MONO_ADD_INS (cfg->cbb, ins);
1497 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1498 } else if (!t->byref && (t->type == MONO_TYPE_R8)) {
1499 /* trying to load float value into int registers */
1500 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1D);
1501 ins->dreg = mono_alloc_ireg (cfg);
1502 ins->sreg1 = in->dreg;
1503 MONO_ADD_INS (cfg->cbb, ins);
1504 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1505 } else {
1506 MONO_INST_NEW (cfg, ins, OP_MOVE);
1507 ins->dreg = mono_alloc_ireg (cfg);
1508 ins->sreg1 = in->dreg;
1509 MONO_ADD_INS (cfg->cbb, ins);
1510 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1512 } else if (ainfo->regtype == RegTypeStructByAddr) {
1513 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1514 ins->opcode = OP_OUTARG_VT;
1515 ins->sreg1 = in->dreg;
1516 ins->klass = in->klass;
1517 ins->inst_p0 = call;
1518 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1519 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1520 MONO_ADD_INS (cfg->cbb, ins);
1521 } else if (ainfo->regtype == RegTypeStructByVal) {
1522 /* this is further handled in mono_arch_emit_outarg_vt () */
1523 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1524 ins->opcode = OP_OUTARG_VT;
1525 ins->sreg1 = in->dreg;
1526 ins->klass = in->klass;
1527 ins->inst_p0 = call;
1528 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1529 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1530 MONO_ADD_INS (cfg->cbb, ins);
1531 } else if (ainfo->regtype == RegTypeBase) {
1532 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1533 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1534 } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1535 if (t->type == MONO_TYPE_R8)
1536 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1537 else
1538 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1539 } else {
1540 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1542 } else if (ainfo->regtype == RegTypeFP) {
1543 if (t->type == MONO_TYPE_VALUETYPE) {
1544 /* this is further handled in mono_arch_emit_outarg_vt () */
1545 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1546 ins->opcode = OP_OUTARG_VT;
1547 ins->sreg1 = in->dreg;
1548 ins->klass = in->klass;
1549 ins->inst_p0 = call;
1550 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1551 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1552 MONO_ADD_INS (cfg->cbb, ins);
1554 cfg->flags |= MONO_CFG_HAS_FPOUT;
1555 } else {
1556 int dreg = mono_alloc_freg (cfg);
1558 if (ainfo->size == 4) {
1559 MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, dreg, in->dreg);
1560 } else {
1561 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1562 ins->dreg = dreg;
1563 ins->sreg1 = in->dreg;
1564 MONO_ADD_INS (cfg->cbb, ins);
1567 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1568 cfg->flags |= MONO_CFG_HAS_FPOUT;
1570 } else {
1571 g_assert_not_reached ();
1575 /* Emit the signature cookie in the case that there is no
1576 additional argument */
1577 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1578 emit_sig_cookie (cfg, call, cinfo);
1580 if (cinfo->struct_ret) {
1581 MonoInst *vtarg;
1583 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1584 vtarg->sreg1 = call->vret_var->dreg;
1585 vtarg->dreg = mono_alloc_preg (cfg);
1586 MONO_ADD_INS (cfg->cbb, vtarg);
1588 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1590 #if 0
1592 * Reverse the call->out_args list.
1595 MonoInst *prev = NULL, *list = call->out_args, *next;
1596 while (list) {
1597 next = list->next;
1598 list->next = prev;
1599 prev = list;
1600 list = next;
1602 call->out_args = prev;
1604 #endif
1605 call->stack_usage = cinfo->stack_usage;
1606 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1607 #if _MIPS_SIM == _ABIO32
1608 /* a0-a3 always present */
1609 cfg->param_area = MAX (cfg->param_area, 4 * SIZEOF_REGISTER);
1610 #endif
1611 cfg->param_area = (cfg->param_area + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1612 cfg->flags |= MONO_CFG_HAS_CALLS;
1614 * should set more info in call, such as the stack space
1615 * used by the args that needs to be added back to esp
1618 g_free (cinfo);
1621 void
1622 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1624 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1625 ArgInfo *ainfo = ins->inst_p1;
1626 int ovf_size = ainfo->vtsize;
1627 int doffset = ainfo->offset;
1628 int i, soffset, dreg;
1630 if (ainfo->regtype == RegTypeStructByVal) {
1631 #if 1
1632 if (cfg->verbose_level > 0) {
1633 char* nm = mono_method_full_name (cfg->method, TRUE);
1634 g_print ("Method %s outarg_vt struct doffset=%d ainfo->size=%d ovf_size=%d\n",
1635 nm, doffset, ainfo->size, ovf_size);
1636 g_free (nm);
1638 #endif
1640 soffset = 0;
1641 for (i = 0; i < ainfo->size; ++i) {
1642 dreg = mono_alloc_ireg (cfg);
1643 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1644 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1645 soffset += SIZEOF_REGISTER;
1647 if (ovf_size != 0) {
1648 mini_emit_memcpy (cfg, mips_fp, doffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
1650 } else if (ainfo->regtype == RegTypeFP) {
1651 int tmpr = mono_alloc_freg (cfg);
1653 if (ainfo->size == 4)
1654 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1655 else
1656 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1657 dreg = mono_alloc_freg (cfg);
1658 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1659 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1660 } else {
1661 MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
1662 MonoInst *load;
1663 guint32 size;
1665 /* FIXME: alignment? */
1666 if (call->signature->pinvoke) {
1667 size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
1668 vtcopy->backend.is_pinvoke = 1;
1669 } else {
1670 size = mini_type_stack_size (cfg->generic_sharing_context, &src->klass->byval_arg, NULL);
1672 if (size > 0)
1673 g_assert (ovf_size > 0);
1675 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1676 mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, size, 0);
1678 if (ainfo->offset)
1679 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_at, ainfo->offset, load->dreg);
1680 else
1681 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1685 void
1686 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1688 MonoType *ret = mini_type_get_underlying_type (cfg->generic_sharing_context,
1689 mono_method_signature (method)->ret);
1691 if (!ret->byref) {
1692 #if (SIZEOF_REGISTER == 4)
1693 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1694 MonoInst *ins;
1696 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1697 ins->sreg1 = val->dreg + 1;
1698 ins->sreg2 = val->dreg + 2;
1699 MONO_ADD_INS (cfg->cbb, ins);
1700 return;
1702 #endif
1703 if (ret->type == MONO_TYPE_R8) {
1704 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1705 return;
1707 if (ret->type == MONO_TYPE_R4) {
1708 MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, cfg->ret->dreg, val->dreg);
1709 return;
1712 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1715 void
1716 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1718 MonoInst *ins, *n, *last_ins = NULL;
1720 if (cfg->verbose_level > 2)
1721 g_print ("Basic block %d peephole pass 1\n", bb->block_num);
1723 ins = bb->code;
1724 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1725 if (cfg->verbose_level > 2)
1726 mono_print_ins_index (0, ins);
1728 switch (ins->opcode) {
1729 #if 0
1730 case OP_LOAD_MEMBASE:
1731 case OP_LOADI4_MEMBASE:
1733 * OP_IADD reg2, reg1, const1
1734 * OP_LOAD_MEMBASE const2(reg2), reg3
1735 * ->
1736 * OP_LOAD_MEMBASE (const1+const2)(reg1), reg3
1738 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)){
1739 int const1 = last_ins->inst_imm;
1740 int const2 = ins->inst_offset;
1742 if (mips_is_imm16 (const1 + const2)) {
1743 ins->inst_basereg = last_ins->sreg1;
1744 ins->inst_offset = const1 + const2;
1747 break;
1748 #endif
1751 last_ins = ins;
1752 ins = ins->next;
1754 bb->last_ins = last_ins;
1757 void
1758 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
1760 MonoInst *ins, *n, *last_ins = NULL;
1761 ins = bb->code;
1763 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1764 MonoInst *last_ins = ins->prev;
1766 switch (ins->opcode) {
1767 case OP_MUL_IMM:
1768 /* remove unnecessary multiplication with 1 */
1769 if (ins->inst_imm == 1) {
1770 if (ins->dreg != ins->sreg1) {
1771 ins->opcode = OP_MOVE;
1772 } else {
1773 MONO_DELETE_INS (bb, ins);
1774 continue;
1776 } else {
1777 int power2 = mono_is_power_of_two (ins->inst_imm);
1778 if (power2 > 0) {
1779 ins->opcode = OP_SHL_IMM;
1780 ins->inst_imm = power2;
1783 break;
1784 case OP_LOAD_MEMBASE:
1785 case OP_LOADI4_MEMBASE:
1787 * OP_STORE_MEMBASE_REG reg, offset(basereg)
1788 * OP_LOAD_MEMBASE offset(basereg), reg
1790 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
1791 || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
1792 ins->inst_basereg == last_ins->inst_destbasereg &&
1793 ins->inst_offset == last_ins->inst_offset) {
1794 if (ins->dreg == last_ins->sreg1) {
1795 MONO_DELETE_INS (bb, ins);
1796 continue;
1797 } else {
1798 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1799 ins->opcode = OP_MOVE;
1800 ins->sreg1 = last_ins->sreg1;
1802 break;
1805 * Note: reg1 must be different from the basereg in the second load
1806 * OP_LOAD_MEMBASE offset(basereg), reg1
1807 * OP_LOAD_MEMBASE offset(basereg), reg2
1808 * -->
1809 * OP_LOAD_MEMBASE offset(basereg), reg1
1810 * OP_MOVE reg1, reg2
1812 if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
1813 || last_ins->opcode == OP_LOAD_MEMBASE) &&
1814 ins->inst_basereg != last_ins->dreg &&
1815 ins->inst_basereg == last_ins->inst_basereg &&
1816 ins->inst_offset == last_ins->inst_offset) {
1818 if (ins->dreg == last_ins->dreg) {
1819 MONO_DELETE_INS (bb, ins);
1820 continue;
1821 } else {
1822 ins->opcode = OP_MOVE;
1823 ins->sreg1 = last_ins->dreg;
1826 //g_assert_not_reached ();
1827 break;
1829 #if 0
1831 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1832 * OP_LOAD_MEMBASE offset(basereg), reg
1833 * -->
1834 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1835 * OP_ICONST reg, imm
1837 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
1838 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
1839 ins->inst_basereg == last_ins->inst_destbasereg &&
1840 ins->inst_offset == last_ins->inst_offset) {
1841 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1842 ins->opcode = OP_ICONST;
1843 ins->inst_c0 = last_ins->inst_imm;
1844 g_assert_not_reached (); // check this rule
1845 break;
1847 #endif
1848 break;
1849 case OP_LOADU1_MEMBASE:
1850 case OP_LOADI1_MEMBASE:
1851 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
1852 ins->inst_basereg == last_ins->inst_destbasereg &&
1853 ins->inst_offset == last_ins->inst_offset) {
1854 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
1855 ins->sreg1 = last_ins->sreg1;
1857 break;
1858 case OP_LOADU2_MEMBASE:
1859 case OP_LOADI2_MEMBASE:
1860 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
1861 ins->inst_basereg == last_ins->inst_destbasereg &&
1862 ins->inst_offset == last_ins->inst_offset) {
1863 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
1864 ins->sreg1 = last_ins->sreg1;
1866 break;
1867 case OP_ICONV_TO_I4:
1868 case OP_ICONV_TO_U4:
1869 case OP_MOVE:
1870 ins->opcode = OP_MOVE;
1872 * OP_MOVE reg, reg
1874 if (ins->dreg == ins->sreg1) {
1875 MONO_DELETE_INS (bb, ins);
1876 continue;
1879 * OP_MOVE sreg, dreg
1880 * OP_MOVE dreg, sreg
1882 if (last_ins && last_ins->opcode == OP_MOVE &&
1883 ins->sreg1 == last_ins->dreg &&
1884 ins->dreg == last_ins->sreg1) {
1885 MONO_DELETE_INS (bb, ins);
1886 continue;
1888 break;
1890 last_ins = ins;
1891 ins = ins->next;
1893 bb->last_ins = last_ins;
1896 void
1897 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins)
1899 int tmp1 = -1;
1900 int tmp2 = -1;
1901 int tmp3 = -1;
1902 int tmp4 = -1;
1903 int tmp5 = -1;
1905 switch (ins->opcode) {
1906 #if 0
1907 case OP_LCOMPARE:
1908 case OP_LCOMPARE_IMM:
1909 mono_print_ins (ins);
1910 g_assert_not_reached ();
1911 #endif
1912 case OP_LADD:
1913 tmp1 = mono_alloc_ireg (cfg);
1914 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
1915 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
1916 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
1917 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
1918 ins->opcode = OP_NOP;
1919 break;
1921 case OP_LADD_IMM:
1922 tmp1 = mono_alloc_ireg (cfg);
1923 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
1924 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
1925 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
1926 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
1927 ins->opcode = OP_NOP;
1928 break;
1930 case OP_LSUB:
1931 tmp1 = mono_alloc_ireg (cfg);
1932 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
1933 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
1934 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
1935 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
1936 ins->opcode = OP_NOP;
1937 break;
1939 case OP_LSUB_IMM:
1940 tmp1 = mono_alloc_ireg (cfg);
1941 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
1942 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
1943 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
1944 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
1945 ins->opcode = OP_NOP;
1946 break;
1948 case OP_LMUL:
1949 case OP_LDIV:
1950 case OP_LDIV_UN:
1951 case OP_LREM:
1952 case OP_LREM_UN:
1953 case OP_LSHL:
1954 case OP_LSHR:
1955 case OP_LSHR_UN:
1956 mono_print_ins (ins);
1957 g_assert_not_reached ();
1959 case OP_LNEG:
1960 tmp1 = mono_alloc_ireg (cfg);
1961 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, mips_zero, ins->sreg1+1);
1962 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, mips_zero, ins->dreg+1);
1963 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, mips_zero, ins->sreg1+2);
1964 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
1965 ins->opcode = OP_NOP;
1966 break;
1968 #if 0
1969 case OP_LNOT:
1970 #endif
1971 #if 0
1972 case OP_LCONV_TO_I1:
1973 case OP_LCONV_TO_I2:
1974 case OP_LCONV_TO_I4:
1975 case OP_LCONV_TO_I8:
1976 case OP_LCONV_TO_R4:
1977 case OP_LCONV_TO_R8:
1978 case OP_LCONV_TO_U4:
1979 case OP_LCONV_TO_U8:
1980 case OP_LCONV_TO_U2:
1981 case OP_LCONV_TO_U1:
1982 case OP_LCONV_TO_I:
1983 case OP_LCONV_TO_OVF_I:
1984 case OP_LCONV_TO_OVF_U:
1985 #endif
1986 mono_print_ins (ins);
1987 g_assert_not_reached ();
1989 case OP_LADD_OVF:
1990 tmp1 = mono_alloc_ireg (cfg);
1991 tmp2 = mono_alloc_ireg (cfg);
1992 tmp3 = mono_alloc_ireg (cfg);
1993 tmp4 = mono_alloc_ireg (cfg);
1994 tmp5 = mono_alloc_ireg (cfg);
1996 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
1998 /* tmp1 holds the carry from the low 32-bit to the high 32-bits */
1999 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->dreg+1, ins->sreg1+1);
2001 /* add the high 32-bits, and add in the carry from the low 32-bits */
2002 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2003 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp5, ins->dreg+2);
2005 /* Overflow happens if
2006 * neg + neg = pos or
2007 * pos + pos = neg
2008 * XOR of the high bits returns 0 if the signs match
2009 * XOR of that with the high bit of the result return 1 if overflow.
2012 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2013 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2015 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2016 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg+2, ins->sreg2+2);
2017 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp2, tmp2);
2019 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2020 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp3, tmp2, tmp1);
2021 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2023 /* Now, if (tmp4 == 0) then overflow */
2024 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp4, mips_zero, "OverflowException");
2025 ins->opcode = OP_NOP;
2026 break;
2028 case OP_LADD_OVF_UN:
2029 tmp1 = mono_alloc_ireg (cfg);
2030 tmp2 = mono_alloc_ireg (cfg);
2032 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2033 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2034 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2035 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp1, ins->dreg+2);
2036 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->dreg+2, ins->sreg1+2);
2037 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2038 ins->opcode = OP_NOP;
2039 break;
2041 case OP_LMUL_OVF:
2042 case OP_LMUL_OVF_UN:
2043 mono_print_ins (ins);
2044 g_assert_not_reached ();
2046 case OP_LSUB_OVF:
2047 tmp1 = mono_alloc_ireg (cfg);
2048 tmp2 = mono_alloc_ireg (cfg);
2049 tmp3 = mono_alloc_ireg (cfg);
2050 tmp4 = mono_alloc_ireg (cfg);
2051 tmp5 = mono_alloc_ireg (cfg);
2053 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2055 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->sreg1+1, ins->dreg+1);
2056 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2057 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp5);
2059 /* Overflow happens if
2060 * neg - pos = pos or
2061 * pos - neg = neg
2062 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2064 * tmp1 = (lhs ^ rhs)
2065 * tmp2 = (lhs ^ result)
2066 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2069 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2070 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1+2, ins->dreg+2);
2071 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp3, tmp2, tmp1);
2072 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2074 /* Now, if (tmp4 == 1) then overflow */
2075 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp4, mips_zero, "OverflowException");
2076 ins->opcode = OP_NOP;
2077 break;
2079 case OP_LSUB_OVF_UN:
2080 tmp1 = mono_alloc_ireg (cfg);
2081 tmp2 = mono_alloc_ireg (cfg);
2083 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2084 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2085 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2086 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2088 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->sreg1+2, ins->dreg+2);
2089 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2090 ins->opcode = OP_NOP;
2091 break;
2092 #if 0
2093 case OP_LCONV_TO_OVF_I1_UN:
2094 case OP_LCONV_TO_OVF_I2_UN:
2095 case OP_LCONV_TO_OVF_I4_UN:
2096 case OP_LCONV_TO_OVF_I8_UN:
2097 case OP_LCONV_TO_OVF_U1_UN:
2098 case OP_LCONV_TO_OVF_U2_UN:
2099 case OP_LCONV_TO_OVF_U4_UN:
2100 case OP_LCONV_TO_OVF_U8_UN:
2101 case OP_LCONV_TO_OVF_I_UN:
2102 case OP_LCONV_TO_OVF_U_UN:
2103 case OP_LCONV_TO_OVF_I1:
2104 case OP_LCONV_TO_OVF_U1:
2105 case OP_LCONV_TO_OVF_I2:
2106 case OP_LCONV_TO_OVF_U2:
2107 case OP_LCONV_TO_OVF_I4:
2108 case OP_LCONV_TO_OVF_U4:
2109 case OP_LCONV_TO_OVF_I8:
2110 case OP_LCONV_TO_OVF_U8:
2111 #endif
2112 case OP_LCEQ:
2113 case OP_LCGT:
2114 case OP_LCGT_UN:
2115 case OP_LCLT:
2116 case OP_LCLT_UN:
2117 #if 0
2118 case OP_LCONV_TO_R_UN:
2119 case OP_LCONV_TO_U:
2120 #endif
2121 case OP_LMUL_IMM:
2122 case OP_LSHL_IMM:
2123 case OP_LSHR_IMM:
2124 case OP_LSHR_UN_IMM:
2125 case OP_LDIV_IMM:
2126 case OP_LDIV_UN_IMM:
2127 case OP_LREM_IMM:
2128 case OP_LREM_UN_IMM:
2129 case OP_LBEQ:
2130 case OP_LBGE:
2131 case OP_LBGT:
2132 case OP_LBLE:
2133 case OP_LBLT:
2134 case OP_LBNE_UN:
2135 case OP_LBGE_UN:
2136 case OP_LBGT_UN:
2137 case OP_LBLE_UN:
2138 case OP_LBLT_UN:
2139 mono_print_ins (ins);
2140 g_assert_not_reached ();
2141 #if 0
2142 case OP_LCONV_TO_R8_2:
2143 case OP_LCONV_TO_R4_2:
2144 case OP_LCONV_TO_R_UN_2:
2145 #endif
2146 case OP_LCONV_TO_OVF_I4_2:
2147 tmp1 = mono_alloc_ireg (cfg);
2149 /* Overflows if reg2 != sign extension of reg1 */
2150 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp1, ins->sreg1, 31);
2151 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, ins->sreg2, tmp1, "OverflowException");
2152 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
2153 ins->opcode = OP_NOP;
2154 break;
2156 case OP_LMIN_UN:
2157 case OP_LMAX_UN:
2158 case OP_LMIN:
2159 case OP_LMAX:
2160 mono_print_ins (ins);
2161 g_assert_not_reached ();
2163 default:
2164 break;
2168 void
2169 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
2171 int tmp1 = -1;
2172 int tmp2 = -1;
2173 int tmp3 = -1;
2174 int tmp4 = -1;
2175 int tmp5 = -1;
2177 switch (ins->opcode) {
2178 case OP_IADD_OVF:
2179 tmp1 = mono_alloc_ireg (cfg);
2180 tmp2 = mono_alloc_ireg (cfg);
2181 tmp3 = mono_alloc_ireg (cfg);
2182 tmp4 = mono_alloc_ireg (cfg);
2183 tmp5 = mono_alloc_ireg (cfg);
2185 /* add the operands */
2187 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2189 /* Overflow happens if
2190 * neg + neg = pos or
2191 * pos + pos = neg
2193 * (bit31s of operands match) AND (bit31 of operand != bit31 of result)
2194 * XOR of the high bit returns 0 if the signs match
2195 * XOR of that with the high bit of the result return 1 if overflow.
2198 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2199 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2201 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2202 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg, ins->sreg2);
2203 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp3, tmp2);
2205 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2206 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp4, tmp3, tmp1);
2208 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp5, tmp4, 31);
2210 /* Now, if (tmp4 == 0) then overflow */
2211 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp5, mips_zero, "OverflowException");
2212 ins->opcode = OP_NOP;
2213 break;
2215 case OP_IADD_OVF_UN:
2216 tmp1 = mono_alloc_ireg (cfg);
2218 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2219 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg, ins->sreg1);
2220 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2221 ins->opcode = OP_NOP;
2222 break;
2224 case OP_ISUB_OVF:
2225 tmp1 = mono_alloc_ireg (cfg);
2226 tmp2 = mono_alloc_ireg (cfg);
2227 tmp3 = mono_alloc_ireg (cfg);
2228 tmp4 = mono_alloc_ireg (cfg);
2229 tmp5 = mono_alloc_ireg (cfg);
2231 /* add the operands */
2233 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2235 /* Overflow happens if
2236 * neg - pos = pos or
2237 * pos - neg = neg
2238 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2240 * tmp1 = (lhs ^ rhs)
2241 * tmp2 = (lhs ^ result)
2242 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2245 /* tmp3 = 1 if the signs of the two inputs differ */
2246 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2247 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1, ins->dreg);
2248 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp3, tmp1, 0);
2249 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp4, tmp2, 0);
2250 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp5, tmp4, tmp3);
2252 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp5, mips_zero, "OverflowException");
2253 ins->opcode = OP_NOP;
2254 break;
2256 case OP_ISUB_OVF_UN:
2257 tmp1 = mono_alloc_ireg (cfg);
2259 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2260 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1, ins->dreg);
2261 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2262 ins->opcode = OP_NOP;
2263 break;
2268 static int
2269 map_to_reg_reg_op (int op)
2271 switch (op) {
2272 case OP_ADD_IMM:
2273 return OP_IADD;
2274 case OP_SUB_IMM:
2275 return OP_ISUB;
2276 case OP_AND_IMM:
2277 return OP_IAND;
2278 case OP_COMPARE_IMM:
2279 return OP_COMPARE;
2280 case OP_ICOMPARE_IMM:
2281 return OP_ICOMPARE;
2282 case OP_LCOMPARE_IMM:
2283 return OP_LCOMPARE;
2284 case OP_ADDCC_IMM:
2285 return OP_IADDCC;
2286 case OP_ADC_IMM:
2287 return OP_IADC;
2288 case OP_SUBCC_IMM:
2289 return OP_ISUBCC;
2290 case OP_SBB_IMM:
2291 return OP_ISBB;
2292 case OP_OR_IMM:
2293 return OP_IOR;
2294 case OP_XOR_IMM:
2295 return OP_IXOR;
2296 case OP_MUL_IMM:
2297 return OP_IMUL;
2298 case OP_LOAD_MEMBASE:
2299 return OP_LOAD_MEMINDEX;
2300 case OP_LOADI4_MEMBASE:
2301 return OP_LOADI4_MEMINDEX;
2302 case OP_LOADU4_MEMBASE:
2303 return OP_LOADU4_MEMINDEX;
2304 case OP_LOADU1_MEMBASE:
2305 return OP_LOADU1_MEMINDEX;
2306 case OP_LOADI2_MEMBASE:
2307 return OP_LOADI2_MEMINDEX;
2308 case OP_LOADU2_MEMBASE:
2309 return OP_LOADU2_MEMINDEX;
2310 case OP_LOADI1_MEMBASE:
2311 return OP_LOADI1_MEMINDEX;
2312 case OP_LOADR4_MEMBASE:
2313 return OP_LOADR4_MEMINDEX;
2314 case OP_LOADR8_MEMBASE:
2315 return OP_LOADR8_MEMINDEX;
2316 case OP_STOREI1_MEMBASE_REG:
2317 return OP_STOREI1_MEMINDEX;
2318 case OP_STOREI2_MEMBASE_REG:
2319 return OP_STOREI2_MEMINDEX;
2320 case OP_STOREI4_MEMBASE_REG:
2321 return OP_STOREI4_MEMINDEX;
2322 case OP_STORE_MEMBASE_REG:
2323 return OP_STORE_MEMINDEX;
2324 case OP_STORER4_MEMBASE_REG:
2325 return OP_STORER4_MEMINDEX;
2326 case OP_STORER8_MEMBASE_REG:
2327 return OP_STORER8_MEMINDEX;
2328 case OP_STORE_MEMBASE_IMM:
2329 return OP_STORE_MEMBASE_REG;
2330 case OP_STOREI1_MEMBASE_IMM:
2331 return OP_STOREI1_MEMBASE_REG;
2332 case OP_STOREI2_MEMBASE_IMM:
2333 return OP_STOREI2_MEMBASE_REG;
2334 case OP_STOREI4_MEMBASE_IMM:
2335 return OP_STOREI4_MEMBASE_REG;
2336 case OP_STOREI8_MEMBASE_IMM:
2337 return OP_STOREI8_MEMBASE_REG;
2339 return mono_op_imm_to_op (op);
2342 static int
2343 map_to_mips_op (int op)
2345 switch (op) {
2346 case OP_FBEQ:
2347 return OP_MIPS_FBEQ;
2348 case OP_FBGE:
2349 return OP_MIPS_FBGE;
2350 case OP_FBGT:
2351 return OP_MIPS_FBGT;
2352 case OP_FBLE:
2353 return OP_MIPS_FBLE;
2354 case OP_FBLT:
2355 return OP_MIPS_FBLT;
2356 case OP_FBNE_UN:
2357 return OP_MIPS_FBNE;
2358 case OP_FBGE_UN:
2359 return OP_MIPS_FBGE_UN;
2360 case OP_FBGT_UN:
2361 return OP_MIPS_FBGT_UN;
2362 case OP_FBLE_UN:
2363 return OP_MIPS_FBLE_UN;
2364 case OP_FBLT_UN:
2365 return OP_MIPS_FBLT_UN;
2367 case OP_FCEQ:
2368 case OP_FCGT:
2369 case OP_FCGT_UN:
2370 case OP_FCLT:
2371 case OP_FCLT_UN:
2372 default:
2373 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (op), __FUNCTION__);
2374 g_assert_not_reached ();
2378 #define NEW_INS(cfg,after,dest,op) do { \
2379 MONO_INST_NEW((cfg), (dest), (op)); \
2380 mono_bblock_insert_after_ins (bb, (after), (dest)); \
2381 } while (0)
2383 #define INS(pos,op,_dreg,_sreg1,_sreg2) do { \
2384 MonoInst *temp; \
2385 MONO_INST_NEW(cfg, temp, (op)); \
2386 mono_bblock_insert_after_ins (bb, (pos), temp); \
2387 temp->dreg = (_dreg); \
2388 temp->sreg1 = (_sreg1); \
2389 temp->sreg2 = (_sreg2); \
2390 pos = temp; \
2391 } while (0)
2393 #define INS_IMM(pos,op,_dreg,_sreg1,_imm) do { \
2394 MonoInst *temp; \
2395 MONO_INST_NEW(cfg, temp, (op)); \
2396 mono_bblock_insert_after_ins (bb, (pos), temp); \
2397 temp->dreg = (_dreg); \
2398 temp->sreg1 = (_sreg1); \
2399 temp->inst_c0 = (_imm); \
2400 pos = temp; \
2401 } while (0)
2404 * Remove from the instruction list the instructions that can't be
2405 * represented with very simple instructions with no register
2406 * requirements.
2408 void
2409 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2411 MonoInst *ins, *next, *temp, *last_ins = NULL;
2412 int imm;
2414 #if 1
2415 if (cfg->verbose_level > 2) {
2416 int idx = 0;
2418 g_print ("BASIC BLOCK %d (before lowering)\n", bb->block_num);
2419 MONO_BB_FOR_EACH_INS (bb, ins) {
2420 mono_print_ins_index (idx++, ins);
2424 #endif
2426 MONO_BB_FOR_EACH_INS (bb, ins) {
2427 loop_start:
2428 switch (ins->opcode) {
2429 case OP_COMPARE:
2430 case OP_ICOMPARE:
2431 case OP_LCOMPARE:
2432 next = ins->next;
2433 /* Branch opts can eliminate the branch */
2434 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2435 ins->opcode = OP_NOP;
2436 break;
2438 break;
2440 case OP_COMPARE_IMM:
2441 case OP_ICOMPARE_IMM:
2442 case OP_LCOMPARE_IMM:
2443 next = ins->next;
2444 /* Branch opts can eliminate the branch */
2445 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2446 ins->opcode = OP_NOP;
2447 break;
2449 if (ins->inst_imm) {
2450 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2451 temp->inst_c0 = ins->inst_imm;
2452 temp->dreg = mono_alloc_ireg (cfg);
2453 ins->sreg2 = temp->dreg;
2454 last_ins = temp;
2456 else {
2457 ins->sreg2 = mips_zero;
2459 if (ins->opcode == OP_COMPARE_IMM)
2460 ins->opcode = OP_COMPARE;
2461 else if (ins->opcode == OP_ICOMPARE_IMM)
2462 ins->opcode = OP_ICOMPARE;
2463 else if (ins->opcode == OP_LCOMPARE_IMM)
2464 ins->opcode = OP_LCOMPARE;
2465 goto loop_start;
2467 case OP_IDIV_UN_IMM:
2468 case OP_IDIV_IMM:
2469 case OP_IREM_IMM:
2470 case OP_IREM_UN_IMM:
2471 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2472 temp->inst_c0 = ins->inst_imm;
2473 temp->dreg = mono_alloc_ireg (cfg);
2474 ins->sreg2 = temp->dreg;
2475 if (ins->opcode == OP_IDIV_IMM)
2476 ins->opcode = OP_IDIV;
2477 else if (ins->opcode == OP_IREM_IMM)
2478 ins->opcode = OP_IREM;
2479 else if (ins->opcode == OP_IDIV_UN_IMM)
2480 ins->opcode = OP_IDIV_UN;
2481 else if (ins->opcode == OP_IREM_UN_IMM)
2482 ins->opcode = OP_IREM_UN;
2483 last_ins = temp;
2484 /* handle rem separately */
2485 goto loop_start;
2487 #if 0
2488 case OP_AND_IMM:
2489 case OP_OR_IMM:
2490 case OP_XOR_IMM:
2491 if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
2492 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2493 temp->inst_c0 = ins->inst_imm;
2494 temp->dreg = mono_alloc_ireg (cfg);
2495 ins->sreg2 = temp->dreg;
2496 ins->opcode = map_to_reg_reg_op (ins->opcode);
2498 break;
2499 #endif
2500 case OP_AND_IMM:
2501 case OP_IAND_IMM:
2502 case OP_OR_IMM:
2503 case OP_IOR_IMM:
2504 case OP_XOR_IMM:
2505 case OP_IXOR_IMM:
2506 /* unsigned 16 bit immediate */
2507 if (ins->inst_imm & 0xffff0000) {
2508 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2509 temp->inst_c0 = ins->inst_imm;
2510 temp->dreg = mono_alloc_ireg (cfg);
2511 ins->sreg2 = temp->dreg;
2512 ins->opcode = map_to_reg_reg_op (ins->opcode);
2514 break;
2516 case OP_IADD_IMM:
2517 case OP_ADD_IMM:
2518 case OP_ADDCC_IMM:
2519 /* signed 16 bit immediate */
2520 if (!mips_is_imm16 (ins->inst_imm)) {
2521 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2522 temp->inst_c0 = ins->inst_imm;
2523 temp->dreg = mono_alloc_ireg (cfg);
2524 ins->sreg2 = temp->dreg;
2525 ins->opcode = map_to_reg_reg_op (ins->opcode);
2527 break;
2529 case OP_SUB_IMM:
2530 case OP_ISUB_IMM:
2531 if (!mips_is_imm16 (-ins->inst_imm)) {
2532 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2533 temp->inst_c0 = ins->inst_imm;
2534 temp->dreg = mono_alloc_ireg (cfg);
2535 ins->sreg2 = temp->dreg;
2536 ins->opcode = map_to_reg_reg_op (ins->opcode);
2538 break;
2540 case OP_MUL_IMM:
2541 case OP_IMUL_IMM:
2542 if (ins->inst_imm == 1) {
2543 ins->opcode = OP_MOVE;
2544 break;
2546 if (ins->inst_imm == 0) {
2547 ins->opcode = OP_ICONST;
2548 ins->inst_c0 = 0;
2549 break;
2551 imm = mono_is_power_of_two (ins->inst_imm);
2552 if (imm > 0) {
2553 ins->opcode = OP_SHL_IMM;
2554 ins->inst_imm = imm;
2555 break;
2557 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2558 temp->inst_c0 = ins->inst_imm;
2559 temp->dreg = mono_alloc_ireg (cfg);
2560 ins->sreg2 = temp->dreg;
2561 ins->opcode = map_to_reg_reg_op (ins->opcode);
2562 break;
2564 case OP_LOCALLOC_IMM:
2565 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2566 temp->inst_c0 = ins->inst_imm;
2567 temp->dreg = mono_alloc_ireg (cfg);
2568 ins->sreg1 = temp->dreg;
2569 ins->opcode = OP_LOCALLOC;
2570 break;
2572 case OP_LOAD_MEMBASE:
2573 case OP_LOADI4_MEMBASE:
2574 case OP_LOADU4_MEMBASE:
2575 case OP_LOADI2_MEMBASE:
2576 case OP_LOADU2_MEMBASE:
2577 case OP_LOADI1_MEMBASE:
2578 case OP_LOADU1_MEMBASE:
2579 case OP_LOADR4_MEMBASE:
2580 case OP_LOADR8_MEMBASE:
2581 case OP_STORE_MEMBASE_REG:
2582 case OP_STOREI4_MEMBASE_REG:
2583 case OP_STOREI2_MEMBASE_REG:
2584 case OP_STOREI1_MEMBASE_REG:
2585 case OP_STORER4_MEMBASE_REG:
2586 case OP_STORER8_MEMBASE_REG:
2587 /* we can do two things: load the immed in a register
2588 * and use an indexed load, or see if the immed can be
2589 * represented as an ad_imm + a load with a smaller offset
2590 * that fits. We just do the first for now, optimize later.
2592 if (mips_is_imm16 (ins->inst_offset))
2593 break;
2594 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2595 temp->inst_c0 = ins->inst_offset;
2596 temp->dreg = mono_alloc_ireg (cfg);
2597 ins->sreg2 = temp->dreg;
2598 ins->opcode = map_to_reg_reg_op (ins->opcode);
2599 break;
2601 case OP_STORE_MEMBASE_IMM:
2602 case OP_STOREI1_MEMBASE_IMM:
2603 case OP_STOREI2_MEMBASE_IMM:
2604 case OP_STOREI4_MEMBASE_IMM:
2605 case OP_STOREI8_MEMBASE_IMM:
2606 if (!ins->inst_imm) {
2607 ins->sreg1 = mips_zero;
2608 ins->opcode = map_to_reg_reg_op (ins->opcode);
2610 else {
2611 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2612 temp->inst_c0 = ins->inst_imm;
2613 temp->dreg = mono_alloc_ireg (cfg);
2614 ins->sreg1 = temp->dreg;
2615 ins->opcode = map_to_reg_reg_op (ins->opcode);
2616 last_ins = temp;
2617 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2619 break;
2621 case OP_FCOMPARE:
2622 next = ins->next;
2623 /* Branch opts can eliminate the branch */
2624 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2625 ins->opcode = OP_NOP;
2626 break;
2628 g_assert(next);
2631 * remap compare/branch and compare/set
2632 * to MIPS specific opcodes.
2634 ins->opcode = OP_NOP;
2635 next->opcode = map_to_mips_op (next->opcode);
2636 next->sreg1 = ins->sreg1;
2637 next->sreg2 = ins->sreg2;
2638 break;
2640 #if 0
2641 case OP_R8CONST:
2642 case OP_R4CONST:
2643 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2644 temp->inst_c0 = (guint32)ins->inst_p0;
2645 temp->dreg = mono_alloc_ireg (cfg);
2646 ins->inst_basereg = temp->dreg;
2647 ins->inst_offset = 0;
2648 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2649 last_ins = temp;
2650 /* make it handle the possibly big ins->inst_offset
2651 * later optimize to use lis + load_membase
2653 goto loop_start;
2654 #endif
2655 case OP_IBEQ:
2656 g_assert (ins_is_compare(last_ins));
2657 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->sreg1, last_ins->sreg2);
2658 last_ins->opcode = OP_NOP;
2659 break;
2661 case OP_IBNE_UN:
2662 g_assert (ins_is_compare(last_ins));
2663 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->sreg1, last_ins->sreg2);
2664 last_ins->opcode = OP_NOP;
2665 break;
2667 case OP_IBGE:
2668 g_assert (ins_is_compare(last_ins));
2669 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2670 last_ins->dreg = mono_alloc_ireg (cfg);
2671 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2672 break;
2674 case OP_IBGE_UN:
2675 g_assert (ins_is_compare(last_ins));
2676 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2677 last_ins->dreg = mono_alloc_ireg (cfg);
2678 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2679 break;
2681 case OP_IBLT:
2682 g_assert (ins_is_compare(last_ins));
2683 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2684 last_ins->dreg = mono_alloc_ireg (cfg);
2685 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2686 break;
2688 case OP_IBLT_UN:
2689 g_assert (ins_is_compare(last_ins));
2690 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2691 last_ins->dreg = mono_alloc_ireg (cfg);
2692 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2693 break;
2695 case OP_IBLE:
2696 g_assert (ins_is_compare(last_ins));
2697 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2698 last_ins->dreg = mono_alloc_ireg (cfg);
2699 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2700 break;
2702 case OP_IBLE_UN:
2703 g_assert (ins_is_compare(last_ins));
2704 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2705 last_ins->dreg = mono_alloc_ireg (cfg);
2706 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2707 break;
2709 case OP_IBGT:
2710 g_assert (ins_is_compare(last_ins));
2711 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2712 last_ins->dreg = mono_alloc_ireg (cfg);
2713 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2714 break;
2716 case OP_IBGT_UN:
2717 g_assert (ins_is_compare(last_ins));
2718 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2719 last_ins->dreg = mono_alloc_ireg (cfg);
2720 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2721 break;
2723 case OP_CEQ:
2724 case OP_ICEQ:
2725 g_assert (ins_is_compare(last_ins));
2726 last_ins->opcode = OP_IXOR;
2727 last_ins->dreg = mono_alloc_ireg(cfg);
2728 INS_REWRITE_IMM(ins, OP_MIPS_SLTIU, last_ins->dreg, 1);
2729 break;
2731 case OP_CLT:
2732 case OP_ICLT:
2733 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2734 last_ins->opcode = OP_NOP;
2735 break;
2738 case OP_CLT_UN:
2739 case OP_ICLT_UN:
2740 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2741 last_ins->opcode = OP_NOP;
2742 break;
2744 case OP_CGT:
2745 case OP_ICGT:
2746 g_assert (ins_is_compare(last_ins));
2747 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2748 MONO_DELETE_INS(bb, last_ins);
2749 break;
2751 case OP_CGT_UN:
2752 case OP_ICGT_UN:
2753 g_assert (ins_is_compare(last_ins));
2754 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2755 MONO_DELETE_INS(bb, last_ins);
2756 break;
2758 case OP_COND_EXC_EQ:
2759 case OP_COND_EXC_IEQ:
2760 g_assert (ins_is_compare(last_ins));
2761 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, last_ins->sreg1, last_ins->sreg2);
2762 MONO_DELETE_INS(bb, last_ins);
2763 break;
2765 case OP_COND_EXC_GE:
2766 case OP_COND_EXC_IGE:
2767 g_assert (ins_is_compare(last_ins));
2768 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE, last_ins->sreg1, last_ins->sreg2);
2769 MONO_DELETE_INS(bb, last_ins);
2770 break;
2772 case OP_COND_EXC_GT:
2773 case OP_COND_EXC_IGT:
2774 g_assert (ins_is_compare(last_ins));
2775 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT, last_ins->sreg1, last_ins->sreg2);
2776 MONO_DELETE_INS(bb, last_ins);
2777 break;
2779 case OP_COND_EXC_LE:
2780 case OP_COND_EXC_ILE:
2781 g_assert (ins_is_compare(last_ins));
2782 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE, last_ins->sreg1, last_ins->sreg2);
2783 MONO_DELETE_INS(bb, last_ins);
2784 break;
2786 case OP_COND_EXC_LT:
2787 case OP_COND_EXC_ILT:
2788 g_assert (ins_is_compare(last_ins));
2789 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT, last_ins->sreg1, last_ins->sreg2);
2790 MONO_DELETE_INS(bb, last_ins);
2791 break;
2793 case OP_COND_EXC_NE_UN:
2794 case OP_COND_EXC_INE_UN:
2795 g_assert (ins_is_compare(last_ins));
2796 INS_REWRITE(ins, OP_MIPS_COND_EXC_NE_UN, last_ins->sreg1, last_ins->sreg2);
2797 MONO_DELETE_INS(bb, last_ins);
2798 break;
2800 case OP_COND_EXC_GE_UN:
2801 case OP_COND_EXC_IGE_UN:
2802 g_assert (ins_is_compare(last_ins));
2803 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE_UN, last_ins->sreg1, last_ins->sreg2);
2804 MONO_DELETE_INS(bb, last_ins);
2805 break;
2807 case OP_COND_EXC_GT_UN:
2808 case OP_COND_EXC_IGT_UN:
2809 g_assert (ins_is_compare(last_ins));
2810 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT_UN, last_ins->sreg1, last_ins->sreg2);
2811 MONO_DELETE_INS(bb, last_ins);
2812 break;
2814 case OP_COND_EXC_LE_UN:
2815 case OP_COND_EXC_ILE_UN:
2816 g_assert (ins_is_compare(last_ins));
2817 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE_UN, last_ins->sreg1, last_ins->sreg2);
2818 MONO_DELETE_INS(bb, last_ins);
2819 break;
2821 case OP_COND_EXC_LT_UN:
2822 case OP_COND_EXC_ILT_UN:
2823 g_assert (ins_is_compare(last_ins));
2824 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT_UN, last_ins->sreg1, last_ins->sreg2);
2825 MONO_DELETE_INS(bb, last_ins);
2826 break;
2828 case OP_COND_EXC_OV:
2829 case OP_COND_EXC_IOV: {
2830 int tmp1, tmp2, tmp3, tmp4, tmp5;
2831 MonoInst *pos = last_ins;
2833 /* Overflow happens if
2834 * neg + neg = pos or
2835 * pos + pos = neg
2837 * (bit31s of operands match) AND (bit31 of operand
2838 * != bit31 of result)
2839 * XOR of the high bit returns 0 if the signs match
2840 * XOR of that with the high bit of the result return 1
2841 * if overflow.
2843 g_assert (last_ins->opcode == OP_IADC);
2845 tmp1 = mono_alloc_ireg (cfg);
2846 tmp2 = mono_alloc_ireg (cfg);
2847 tmp3 = mono_alloc_ireg (cfg);
2848 tmp4 = mono_alloc_ireg (cfg);
2849 tmp5 = mono_alloc_ireg (cfg);
2851 /* tmp1 = 0 if the signs of the two inputs match, else 1 */
2852 INS (pos, OP_IXOR, tmp1, last_ins->sreg1, last_ins->sreg2);
2854 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2855 INS (pos, OP_IXOR, tmp2, last_ins->dreg, last_ins->sreg2);
2856 INS (pos, OP_INOT, tmp3, tmp2, -1);
2858 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2859 INS (pos, OP_IOR, tmp4, tmp3, tmp1);
2860 INS_IMM (pos, OP_SHR_IMM, tmp5, tmp4, 31);
2862 /* Now, if (tmp5 == 0) then overflow */
2863 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, tmp5, mips_zero);
2864 ins->dreg = -1;
2865 break;
2868 case OP_COND_EXC_NO:
2869 case OP_COND_EXC_INO:
2870 g_assert_not_reached ();
2871 break;
2873 case OP_COND_EXC_C:
2874 case OP_COND_EXC_IC:
2875 g_assert_not_reached ();
2876 break;
2878 case OP_COND_EXC_NC:
2879 case OP_COND_EXC_INC:
2880 g_assert_not_reached ();
2881 break;
2884 last_ins = ins;
2886 bb->last_ins = last_ins;
2887 bb->max_vreg = cfg->next_vreg;
2889 #if 1
2890 if (cfg->verbose_level > 2) {
2891 int idx = 0;
2893 g_print ("BASIC BLOCK %d (after lowering)\n", bb->block_num);
2894 MONO_BB_FOR_EACH_INS (bb, ins) {
2895 mono_print_ins_index (idx++, ins);
2899 #endif
2903 static guchar*
2904 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
2906 /* sreg is a float, dreg is an integer reg. mips_at is used as scratch */
2907 #if 1
2908 mips_truncwd (code, mips_ftemp, sreg);
2909 #else
2910 mips_cvtwd (code, mips_ftemp, sreg);
2911 #endif
2912 mips_mfc1 (code, dreg, mips_ftemp);
2913 if (!is_signed) {
2914 if (size == 1)
2915 mips_andi (code, dreg, dreg, 0xff);
2916 else if (size == 2) {
2917 mips_sll (code, dreg, dreg, 16);
2918 mips_srl (code, dreg, dreg, 16);
2920 } else {
2921 if (size == 1) {
2922 mips_sll (code, dreg, dreg, 24);
2923 mips_sra (code, dreg, dreg, 24);
2925 else if (size == 2) {
2926 mips_sll (code, dreg, dreg, 16);
2927 mips_sra (code, dreg, dreg, 16);
2930 return code;
2934 * emit_load_volatile_arguments:
2936 * Load volatile arguments from the stack to the original input registers.
2937 * Required before a tail call.
2939 static guint8 *
2940 emit_load_volatile_arguments(MonoCompile *cfg, guint8 *code)
2942 MonoMethod *method = cfg->method;
2943 MonoMethodSignature *sig;
2944 MonoInst *inst;
2945 CallInfo *cinfo;
2946 int i;
2948 sig = mono_method_signature (method);
2949 cinfo = calculate_sizes (sig, sig->pinvoke);
2950 if (cinfo->struct_ret) {
2951 ArgInfo *ainfo = &cinfo->ret;
2952 inst = cfg->vret_addr;
2953 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
2956 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2957 ArgInfo *ainfo = cinfo->args + i;
2958 inst = cfg->args [i];
2959 if (inst->opcode == OP_REGVAR) {
2960 if (ainfo->regtype == RegTypeGeneral)
2961 MIPS_MOVE (code, ainfo->reg, inst->dreg);
2962 else if (ainfo->regtype == RegTypeFP)
2963 g_assert_not_reached();
2964 else if (ainfo->regtype == RegTypeBase) {
2965 /* do nothing */
2966 } else
2967 g_assert_not_reached ();
2968 } else {
2969 if (ainfo->regtype == RegTypeGeneral) {
2970 g_assert (mips_is_imm16 (inst->inst_offset));
2971 switch (ainfo->size) {
2972 case 1:
2973 mips_lb (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
2974 break;
2975 case 2:
2976 mips_lh (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
2977 break;
2978 case 0: /* XXX */
2979 case 4:
2980 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
2981 break;
2982 case 8:
2983 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
2984 mips_lw (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + 4);
2985 break;
2986 default:
2987 g_assert_not_reached ();
2988 break;
2990 } else if (ainfo->regtype == RegTypeBase) {
2991 /* do nothing */
2992 } else if (ainfo->regtype == RegTypeFP) {
2993 g_assert (mips_is_imm16 (inst->inst_offset));
2994 if (ainfo->size == 8) {
2995 #if _MIPS_SIM == _ABIO32
2996 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset+4);
2997 mips_lwc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset);
2998 #elif _MIPS_SIM == _ABIN32
2999 mips_ldc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3000 #endif
3002 else if (ainfo->size == 4)
3003 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3004 else
3005 g_assert_not_reached ();
3006 } else if (ainfo->regtype == RegTypeStructByVal) {
3007 int i;
3008 int doffset = inst->inst_offset;
3010 g_assert (mips_is_imm16 (inst->inst_offset));
3011 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
3012 for (i = 0; i < ainfo->size; ++i) {
3013 mips_lw (code, ainfo->reg + i, inst->inst_basereg, doffset);
3014 doffset += SIZEOF_REGISTER;
3016 } else if (ainfo->regtype == RegTypeStructByAddr) {
3017 g_assert (mips_is_imm16 (inst->inst_offset));
3018 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3019 } else
3020 g_assert_not_reached ();
3024 g_free (cinfo);
3026 return code;
3029 static guint8*
3030 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
3032 int size = cfg->param_area;
3034 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3035 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3037 if (!size)
3038 return code;
3039 #if 0
3040 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3041 if (ppc_is_imm16 (-size)) {
3042 ppc_stwu (code, ppc_r0, -size, ppc_sp);
3043 } else {
3044 ppc_load (code, ppc_r11, -size);
3045 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
3047 #endif
3048 return code;
3051 static guint8*
3052 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
3054 int size = cfg->param_area;
3056 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3057 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3059 if (!size)
3060 return code;
3061 #if 0
3062 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3063 if (ppc_is_imm16 (size)) {
3064 ppc_stwu (code, ppc_r0, size, ppc_sp);
3065 } else {
3066 ppc_load (code, ppc_r11, size);
3067 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
3069 #endif
3070 return code;
3073 void
3074 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3076 MonoInst *ins;
3077 MonoCallInst *call;
3078 guint offset;
3079 guint8 *code = cfg->native_code + cfg->code_len;
3080 MonoInst *last_ins = NULL;
3081 guint last_offset = 0;
3082 int max_len, cpos;
3083 int ins_cnt = 0;
3085 /* we don't align basic blocks of loops on mips */
3087 if (cfg->verbose_level > 2)
3088 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3090 cpos = bb->max_offset;
3092 #if 0
3093 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
3094 MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
3095 g_assert (!mono_compile_aot);
3096 cpos += 20;
3097 if (bb->cil_code)
3098 cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
3099 /* this is not thread save, but good enough */
3100 /* fixme: howto handle overflows? */
3101 mips_load_const (code, mips_at, &cov->data [bb->dfn].count);
3102 mips_lw (code, mips_temp, mips_at, 0);
3103 mips_addiu (code, mips_temp, mips_temp, 1);
3104 mips_sw (code, mips_temp, mips_at, 0);
3106 #endif
3107 MONO_BB_FOR_EACH_INS (bb, ins) {
3108 offset = code - cfg->native_code;
3110 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3112 if (offset > (cfg->code_size - max_len - 16)) {
3113 cfg->code_size *= 2;
3114 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3115 code = cfg->native_code + offset;
3117 mono_debug_record_line_number (cfg, ins, offset);
3118 if (cfg->verbose_level > 2) {
3119 g_print (" @ 0x%x\t", offset);
3120 mono_print_ins_index (ins_cnt++, ins);
3122 /* Check for virtual regs that snuck by */
3123 g_assert ((ins->dreg >= -1) && (ins->dreg < 32));
3125 switch (ins->opcode) {
3126 case OP_RELAXED_NOP:
3127 case OP_NOP:
3128 case OP_DUMMY_USE:
3129 case OP_DUMMY_STORE:
3130 case OP_NOT_REACHED:
3131 case OP_NOT_NULL:
3132 break;
3133 case OP_TLS_GET:
3134 g_assert_not_reached();
3135 #if 0
3136 emit_tls_access (code, ins->dreg, ins->inst_offset);
3137 #endif
3138 break;
3139 case OP_BIGMUL:
3140 mips_mult (code, ins->sreg1, ins->sreg2);
3141 mips_mflo (code, ins->dreg);
3142 mips_mfhi (code, ins->dreg+1);
3143 break;
3144 case OP_BIGMUL_UN:
3145 mips_multu (code, ins->sreg1, ins->sreg2);
3146 mips_mflo (code, ins->dreg);
3147 mips_mfhi (code, ins->dreg+1);
3148 break;
3149 case OP_MEMORY_BARRIER:
3150 #if 0
3151 ppc_sync (code);
3152 #endif
3153 break;
3154 case OP_STOREI1_MEMBASE_IMM:
3155 mips_load_const (code, mips_temp, ins->inst_imm);
3156 if (mips_is_imm16 (ins->inst_offset)) {
3157 mips_sb (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3158 } else {
3159 mips_load_const (code, mips_at, ins->inst_offset);
3160 mips_sb (code, mips_temp, mips_at, ins->inst_destbasereg);
3162 break;
3163 case OP_STOREI2_MEMBASE_IMM:
3164 mips_load_const (code, mips_temp, ins->inst_imm);
3165 if (mips_is_imm16 (ins->inst_offset)) {
3166 mips_sh (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3167 } else {
3168 mips_load_const (code, mips_at, ins->inst_offset);
3169 mips_sh (code, mips_temp, mips_at, ins->inst_destbasereg);
3171 break;
3172 case OP_STOREI8_MEMBASE_IMM:
3173 mips_load_const (code, mips_temp, ins->inst_imm);
3174 if (mips_is_imm16 (ins->inst_offset)) {
3175 mips_sd (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3176 } else {
3177 mips_load_const (code, mips_at, ins->inst_offset);
3178 mips_sd (code, mips_temp, mips_at, ins->inst_destbasereg);
3180 break;
3181 case OP_STORE_MEMBASE_IMM:
3182 case OP_STOREI4_MEMBASE_IMM:
3183 mips_load_const (code, mips_temp, ins->inst_imm);
3184 if (mips_is_imm16 (ins->inst_offset)) {
3185 mips_sw (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3186 } else {
3187 mips_load_const (code, mips_at, ins->inst_offset);
3188 mips_sw (code, mips_temp, mips_at, ins->inst_destbasereg);
3190 break;
3191 case OP_STOREI1_MEMBASE_REG:
3192 if (mips_is_imm16 (ins->inst_offset)) {
3193 mips_sb (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3194 } else {
3195 mips_load_const (code, mips_at, ins->inst_offset);
3196 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3197 mips_sb (code, ins->sreg1, mips_at, 0);
3199 break;
3200 case OP_STOREI2_MEMBASE_REG:
3201 if (mips_is_imm16 (ins->inst_offset)) {
3202 mips_sh (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3203 } else {
3204 mips_load_const (code, mips_at, ins->inst_offset);
3205 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3206 mips_sh (code, ins->sreg1, mips_at, 0);
3208 break;
3209 case OP_STORE_MEMBASE_REG:
3210 case OP_STOREI4_MEMBASE_REG:
3211 if (mips_is_imm16 (ins->inst_offset)) {
3212 mips_sw (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3213 } else {
3214 mips_load_const (code, mips_at, ins->inst_offset);
3215 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3216 mips_sw (code, ins->sreg1, mips_at, 0);
3218 break;
3219 case OP_STOREI8_MEMBASE_REG:
3220 if (mips_is_imm16 (ins->inst_offset)) {
3221 mips_sd (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3222 } else {
3223 mips_load_const (code, mips_at, ins->inst_offset);
3224 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3225 mips_sd (code, ins->sreg1, mips_at, 0);
3227 break;
3228 case OP_LOADU4_MEM:
3229 g_assert_not_reached ();
3230 //x86_mov_reg_imm (code, ins->dreg, ins->inst_p0);
3231 //x86_mov_reg_membase (code, ins->dreg, ins->dreg, 0, 4);
3232 break;
3233 case OP_LOADI8_MEMBASE:
3234 if (mips_is_imm16 (ins->inst_offset)) {
3235 mips_ld (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3236 } else {
3237 mips_load_const (code, mips_at, ins->inst_offset);
3238 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3239 mips_ld (code, ins->dreg, mips_at, 0);
3241 break;
3242 case OP_LOAD_MEMBASE:
3243 case OP_LOADI4_MEMBASE:
3244 case OP_LOADU4_MEMBASE:
3245 if (mips_is_imm16 (ins->inst_offset)) {
3246 mips_lw (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3247 } else {
3248 mips_load_const (code, mips_at, ins->inst_offset);
3249 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3250 mips_lw (code, ins->dreg, mips_at, 0);
3252 break;
3253 case OP_LOADI1_MEMBASE:
3254 if (mips_is_imm16 (ins->inst_offset)) {
3255 mips_lb (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3256 } else {
3257 mips_load_const (code, mips_at, ins->inst_offset);
3258 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3259 mips_lb (code, ins->dreg, mips_at, 0);
3261 break;
3262 case OP_LOADU1_MEMBASE:
3263 if (mips_is_imm16 (ins->inst_offset)) {
3264 mips_lbu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3265 } else {
3266 mips_load_const (code, mips_at, ins->inst_offset);
3267 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3268 mips_lbu (code, ins->dreg, mips_at, 0);
3270 break;
3271 case OP_LOADI2_MEMBASE:
3272 if (mips_is_imm16 (ins->inst_offset)) {
3273 mips_lh (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3274 } else {
3275 mips_load_const (code, mips_at, ins->inst_offset);
3276 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3277 mips_lh (code, ins->dreg, mips_at, 0);
3279 break;
3280 case OP_LOADU2_MEMBASE:
3281 if (mips_is_imm16 (ins->inst_offset)) {
3282 mips_lhu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3283 } else {
3284 mips_load_const (code, mips_at, ins->inst_offset);
3285 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3286 mips_lhu (code, ins->dreg, mips_at, 0);
3288 break;
3289 case OP_ICONV_TO_I1:
3290 mips_sll (code, mips_at, ins->sreg1, 24);
3291 mips_sra (code, ins->dreg, mips_at, 24);
3292 break;
3293 case OP_ICONV_TO_I2:
3294 mips_sll (code, mips_at, ins->sreg1, 16);
3295 mips_sra (code, ins->dreg, mips_at, 16);
3296 break;
3297 case OP_ICONV_TO_U1:
3298 mips_andi (code, ins->dreg, ins->sreg1, 0xff);
3299 break;
3300 case OP_ICONV_TO_U2:
3301 mips_sll (code, mips_at, ins->sreg1, 16);
3302 mips_srl (code, ins->dreg, mips_at, 16);
3303 break;
3304 case OP_MIPS_SLT:
3305 mips_slt (code, ins->dreg, ins->sreg1, ins->sreg2);
3306 break;
3307 case OP_MIPS_SLTI:
3308 g_assert (mips_is_imm16 (ins->inst_imm));
3309 mips_slti (code, ins->dreg, ins->sreg1, ins->inst_imm);
3310 break;
3311 case OP_MIPS_SLTU:
3312 mips_sltu (code, ins->dreg, ins->sreg1, ins->sreg2);
3313 break;
3314 case OP_MIPS_SLTIU:
3315 g_assert (mips_is_imm16 (ins->inst_imm));
3316 mips_sltiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3317 break;
3318 case OP_BREAK:
3319 mips_break (code, 0xfd);
3320 break;
3321 case OP_IADD:
3322 mips_addu (code, ins->dreg, ins->sreg1, ins->sreg2);
3323 break;
3324 case OP_LADD:
3325 mips_daddu (code, ins->dreg, ins->sreg1, ins->sreg2);
3326 break;
3328 case OP_ADD_IMM:
3329 case OP_IADD_IMM:
3330 g_assert (mips_is_imm16 (ins->inst_imm));
3331 mips_addiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3332 break;
3333 case OP_LADD_IMM:
3334 g_assert (mips_is_imm16 (ins->inst_imm));
3335 mips_daddiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3336 break;
3338 case OP_ISUB:
3339 mips_subu (code, ins->dreg, ins->sreg1, ins->sreg2);
3340 break;
3341 case OP_LSUB:
3342 mips_dsubu (code, ins->dreg, ins->sreg1, ins->sreg2);
3343 break;
3345 case OP_ISUB_IMM:
3346 case OP_SUB_IMM:
3347 // we add the negated value
3348 g_assert (mips_is_imm16 (-ins->inst_imm));
3349 mips_addiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3350 break;
3352 case OP_LSUB_IMM:
3353 // we add the negated value
3354 g_assert (mips_is_imm16 (-ins->inst_imm));
3355 mips_daddiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3356 break;
3358 case OP_IAND:
3359 case OP_LAND:
3360 mips_and (code, ins->dreg, ins->sreg1, ins->sreg2);
3361 break;
3363 case OP_AND_IMM:
3364 case OP_IAND_IMM:
3365 case OP_LAND_IMM:
3366 g_assert (!(ins->inst_imm & 0xffff0000));
3367 mips_andi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3368 break;
3370 case OP_IDIV:
3371 case OP_IREM: {
3372 guint32 *divisor_is_m1;
3373 guint32 *divisor_is_zero;
3375 /* */
3376 mips_addiu (code, mips_at, mips_zero, 0xffff);
3377 divisor_is_m1 = (guint32 *)(void *)code;
3378 mips_bne (code, ins->sreg2, mips_at, 0);
3379 mips_nop (code);
3381 /* Divide by -1 -- throw exception */
3382 EMIT_SYSTEM_EXCEPTION_NAME("ArithmeticException");
3384 mips_patch (divisor_is_m1, (guint32)code);
3386 /* Put divide in branch delay slot (NOT YET) */
3387 divisor_is_zero = (guint32 *)(void *)code;
3388 mips_bne (code, ins->sreg2, mips_zero, 0);
3389 mips_nop (code);
3391 /* Divide by zero -- throw exception */
3392 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3394 mips_patch (divisor_is_zero, (guint32)code);
3395 mips_div (code, ins->sreg1, ins->sreg2);
3396 if (ins->opcode == OP_IDIV)
3397 mips_mflo (code, ins->dreg);
3398 else
3399 mips_mfhi (code, ins->dreg);
3400 break;
3402 case OP_IDIV_UN:
3403 case OP_IREM_UN: {
3404 guint32 *divisor_is_zero = (guint32 *)(void *)code;
3406 /* Put divide in branch delay slot (NOT YET) */
3407 mips_bne (code, ins->sreg2, mips_zero, 0);
3408 mips_nop (code);
3410 /* Divide by zero -- throw exception */
3411 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3413 mips_patch (divisor_is_zero, (guint32)code);
3414 mips_divu (code, ins->sreg1, ins->sreg2);
3415 if (ins->opcode == OP_IDIV_UN)
3416 mips_mflo (code, ins->dreg);
3417 else
3418 mips_mfhi (code, ins->dreg);
3419 break;
3421 case OP_DIV_IMM:
3422 g_assert_not_reached ();
3423 #if 0
3424 ppc_load (code, ppc_r11, ins->inst_imm);
3425 ppc_divwod (code, ins->dreg, ins->sreg1, ppc_r11);
3426 ppc_mfspr (code, ppc_r0, ppc_xer);
3427 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3428 /* FIXME: use OverflowException for 0x80000000/-1 */
3429 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3430 #endif
3431 g_assert_not_reached();
3432 break;
3433 case OP_REM_IMM:
3434 g_assert_not_reached ();
3435 case OP_IOR:
3436 mips_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3437 break;
3438 case OP_OR_IMM:
3439 case OP_IOR_IMM:
3440 g_assert (!(ins->inst_imm & 0xffff0000));
3441 mips_ori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3442 break;
3443 case OP_IXOR:
3444 mips_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3445 break;
3446 case OP_XOR_IMM:
3447 case OP_IXOR_IMM:
3448 /* unsigned 16-bit immediate */
3449 g_assert (!(ins->inst_imm & 0xffff0000));
3450 mips_xori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3451 break;
3452 case OP_ISHL:
3453 mips_sllv (code, ins->dreg, ins->sreg1, ins->sreg2);
3454 break;
3455 case OP_SHL_IMM:
3456 case OP_ISHL_IMM:
3457 mips_sll (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3458 break;
3459 case OP_ISHR:
3460 mips_srav (code, ins->dreg, ins->sreg1, ins->sreg2);
3461 break;
3462 case OP_LSHR:
3463 mips_dsrav (code, ins->dreg, ins->sreg1, ins->sreg2);
3464 break;
3465 case OP_SHR_IMM:
3466 case OP_ISHR_IMM:
3467 mips_sra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3468 break;
3469 case OP_LSHR_IMM:
3470 mips_dsra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3471 break;
3472 case OP_SHR_UN_IMM:
3473 case OP_ISHR_UN_IMM:
3474 mips_srl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3475 break;
3476 case OP_LSHR_UN_IMM:
3477 mips_dsrl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3478 break;
3479 case OP_ISHR_UN:
3480 mips_srlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3481 break;
3482 case OP_LSHR_UN:
3483 mips_dsrlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3484 break;
3485 case OP_INOT:
3486 case OP_LNOT:
3487 mips_nor (code, ins->dreg, mips_zero, ins->sreg1);
3488 break;
3489 case OP_INEG:
3490 mips_subu (code, ins->dreg, mips_zero, ins->sreg1);
3491 break;
3492 case OP_LNEG:
3493 mips_dsubu (code, ins->dreg, mips_zero, ins->sreg1);
3494 break;
3495 case OP_IMUL:
3496 #if USE_MUL
3497 mips_mul (code, ins->dreg, ins->sreg1, ins->sreg2);
3498 #else
3499 mips_mult (code, ins->sreg1, ins->sreg2);
3500 mips_mflo (code, ins->dreg);
3501 mips_nop (code);
3502 mips_nop (code);
3503 #endif
3504 break;
3505 #if SIZEOF_REGISTER == 8
3506 case OP_LMUL:
3507 mips_dmult (code, ins->sreg1, ins->sreg2);
3508 mips_mflo (code, ins->dreg);
3509 break;
3510 #endif
3511 case OP_IMUL_OVF: {
3512 guint32 *patch;
3513 mips_mult (code, ins->sreg1, ins->sreg2);
3514 mips_mflo (code, ins->dreg);
3515 mips_mfhi (code, mips_at);
3516 mips_nop (code);
3517 mips_nop (code);
3518 mips_sra (code, mips_temp, ins->dreg, 31);
3519 patch = (guint32 *)(void *)code;
3520 mips_beq (code, mips_temp, mips_at, 0);
3521 mips_nop (code);
3522 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3523 mips_patch (patch, (guint32)code);
3524 break;
3526 case OP_IMUL_OVF_UN:
3527 #if 0
3528 mips_mul (code, ins->dreg, ins->sreg1, ins->sreg2);
3529 #else
3530 mips_mult (code, ins->sreg1, ins->sreg2);
3531 mips_mflo (code, ins->dreg);
3532 mips_mfhi (code, mips_at);
3533 mips_nop (code);
3534 mips_nop (code);
3535 #endif
3536 /* XXX - Throw exception if we overflowed */
3537 break;
3538 case OP_ICONST:
3539 mips_load_const (code, ins->dreg, ins->inst_c0);
3540 break;
3541 #if SIZEOF_REGISTER == 8
3542 case OP_I8CONST:
3543 mips_load_const (code, ins->dreg, ins->inst_c0);
3544 break;
3545 #endif
3546 case OP_AOTCONST:
3547 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3548 mips_load (code, ins->dreg, 0);
3549 break;
3551 case OP_MIPS_MTC1S:
3552 mips_mtc1 (code, ins->dreg, ins->sreg1);
3553 break;
3554 case OP_MIPS_MTC1S_2:
3555 mips_mtc1 (code, ins->dreg, ins->sreg1);
3556 mips_mtc1 (code, ins->dreg+1, ins->sreg2);
3557 break;
3558 case OP_MIPS_MFC1S:
3559 mips_mfc1 (code, ins->dreg, ins->sreg1);
3560 break;
3561 case OP_MIPS_MTC1D:
3562 mips_dmtc1 (code, ins->dreg, ins->sreg1);
3563 break;
3564 case OP_MIPS_MFC1D:
3565 #if 0
3566 mips_dmfc1 (code, ins->dreg, ins->sreg1);
3567 #else
3568 mips_mfc1 (code, ins->dreg+1, ins->sreg1);
3569 mips_mfc1 (code, ins->dreg, ins->sreg1+1);
3570 #endif
3571 break;
3573 case OP_ICONV_TO_I4:
3574 case OP_ICONV_TO_U4:
3575 case OP_MOVE:
3576 if (ins->dreg != ins->sreg1)
3577 MIPS_MOVE (code, ins->dreg, ins->sreg1);
3578 break;
3579 #if SIZEOF_REGISTER == 8
3580 case OP_ZEXT_I4:
3581 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3582 mips_dsrl (code, ins->dreg, ins->dreg, 32);
3583 break;
3584 case OP_SEXT_I4:
3585 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3586 mips_dsra (code, ins->dreg, ins->dreg, 32);
3587 break;
3588 #endif
3589 case OP_SETLRET:
3590 /* Get sreg1 into v1, sreg2 into v0 */
3592 if (ins->sreg1 == mips_v0) {
3593 if (ins->sreg1 != mips_at)
3594 MIPS_MOVE (code, mips_at, ins->sreg1);
3595 if (ins->sreg2 != mips_v0)
3596 MIPS_MOVE (code, mips_v0, ins->sreg2);
3597 MIPS_MOVE (code, mips_v1, mips_at);
3599 else {
3600 if (ins->sreg2 != mips_v0)
3601 MIPS_MOVE (code, mips_v0, ins->sreg2);
3602 if (ins->sreg1 != mips_v1)
3603 MIPS_MOVE (code, mips_v1, ins->sreg1);
3605 break;
3606 case OP_FMOVE:
3607 if (ins->dreg != ins->sreg1) {
3608 mips_fmovd (code, ins->dreg, ins->sreg1);
3610 break;
3611 case OP_MIPS_CVTSD:
3612 /* Convert from double to float and leave it there */
3613 mips_cvtsd (code, ins->dreg, ins->sreg1);
3614 break;
3615 case OP_FCONV_TO_R4:
3616 #if 0
3617 mips_cvtsd (code, ins->dreg, ins->sreg1);
3618 #else
3619 /* Just a move, no precision change */
3620 if (ins->dreg != ins->sreg1) {
3621 mips_fmovd (code, ins->dreg, ins->sreg1);
3623 #endif
3624 break;
3625 case OP_JMP:
3626 code = emit_load_volatile_arguments(cfg, code);
3629 * Pop our stack, then jump to specified method (tail-call)
3630 * Keep in sync with mono_arch_emit_epilog
3632 code = mono_arch_emit_epilog_sub (cfg, code);
3634 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code,
3635 MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3636 #if LONG_BRANCH
3637 mips_lui (code, mips_t9, mips_zero, 0);
3638 mips_addiu (code, mips_t9, mips_t9, 0);
3639 mips_jr (code, mips_t9);
3640 mips_nop (code);
3641 #else
3642 mips_beq (code, mips_zero, mips_zero, 0);
3643 mips_nop (code);
3644 #endif
3645 break;
3646 case OP_CHECK_THIS:
3647 /* ensure ins->sreg1 is not NULL */
3648 mips_lw (code, mips_zero, ins->sreg1, 0);
3649 break;
3650 case OP_ARGLIST: {
3651 if (mips_is_imm16 (cfg->sig_cookie + cfg->stack_usage)) {
3652 mips_addiu (code, mips_at, cfg->frame_reg, cfg->sig_cookie + cfg->stack_usage);
3653 } else {
3654 mips_load_const (code, mips_at, cfg->sig_cookie + cfg->stack_usage);
3655 mips_addu (code, mips_at, cfg->frame_reg, mips_at);
3657 mips_sw (code, mips_at, ins->sreg1, 0);
3658 break;
3660 case OP_FCALL:
3661 case OP_LCALL:
3662 case OP_VCALL:
3663 case OP_VCALL2:
3664 case OP_VOIDCALL:
3665 case OP_CALL:
3666 case OP_FCALL_REG:
3667 case OP_LCALL_REG:
3668 case OP_VCALL_REG:
3669 case OP_VCALL2_REG:
3670 case OP_VOIDCALL_REG:
3671 case OP_CALL_REG:
3672 case OP_FCALL_MEMBASE:
3673 case OP_LCALL_MEMBASE:
3674 case OP_VCALL_MEMBASE:
3675 case OP_VCALL2_MEMBASE:
3676 case OP_VOIDCALL_MEMBASE:
3677 case OP_CALL_MEMBASE:
3678 call = (MonoCallInst*)ins;
3679 switch (ins->opcode) {
3680 case OP_FCALL:
3681 case OP_LCALL:
3682 case OP_VCALL:
3683 case OP_VCALL2:
3684 case OP_VOIDCALL:
3685 case OP_CALL:
3686 if (ins->flags & MONO_INST_HAS_METHOD)
3687 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3688 else
3689 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3690 mips_lui (code, mips_t9, mips_zero, 0);
3691 mips_addiu (code, mips_t9, mips_t9, 0);
3692 break;
3693 case OP_FCALL_REG:
3694 case OP_LCALL_REG:
3695 case OP_VCALL_REG:
3696 case OP_VCALL2_REG:
3697 case OP_VOIDCALL_REG:
3698 case OP_CALL_REG:
3699 MIPS_MOVE (code, mips_t9, ins->sreg1);
3700 break;
3701 case OP_FCALL_MEMBASE:
3702 case OP_LCALL_MEMBASE:
3703 case OP_VCALL_MEMBASE:
3704 case OP_VCALL2_MEMBASE:
3705 case OP_VOIDCALL_MEMBASE:
3706 case OP_CALL_MEMBASE:
3707 mips_lw (code, mips_t9, ins->sreg1, ins->inst_offset);
3708 break;
3710 mips_jalr (code, mips_t9, mips_ra);
3711 mips_nop (code);
3712 #if PROMOTE_R4_TO_R8
3713 /* returned an FP R4 (single), promote to R8 (double) in place */
3714 if ((ins->opcode == OP_FCALL ||
3715 ins->opcode == OP_FCALL_REG) &&
3716 call->signature->ret->type == MONO_TYPE_R4) {
3717 mips_cvtds (code, mips_f0, mips_f0);
3719 #endif
3720 break;
3721 case OP_LOCALLOC: {
3722 int area_offset = cfg->param_area;
3724 /* Round up ins->sreg1, mips_at ends up holding size */
3725 mips_addiu (code, mips_at, ins->sreg1, 31);
3726 mips_addiu (code, mips_temp, mips_zero, ~31);
3727 mips_and (code, mips_at, mips_at, mips_temp);
3729 mips_subu (code, mips_sp, mips_sp, mips_at);
3730 g_assert (mips_is_imm16 (area_offset));
3731 mips_addiu (code, ins->dreg, mips_sp, area_offset);
3733 if (ins->flags & MONO_INST_INIT) {
3734 mips_move (code, mips_temp, ins->dreg);
3735 mips_sb (code, mips_zero, mips_temp, 0);
3736 mips_addiu (code, mips_at, mips_at, -1);
3737 mips_bne (code, mips_at, mips_zero, -3);
3738 mips_addiu (code, mips_temp, mips_temp, 1);
3740 break;
3742 case OP_THROW: {
3743 gpointer addr = mono_arch_get_throw_exception();
3744 mips_move (code, mips_a0, ins->sreg1);
3745 mips_load_const (code, mips_t9, addr);
3746 mips_jalr (code, mips_t9, mips_ra);
3747 mips_nop (code);
3748 mips_break (code, 0xfc);
3749 break;
3751 case OP_RETHROW: {
3752 gpointer addr = mono_arch_get_rethrow_exception();
3753 mips_move (code, mips_a0, ins->sreg1);
3754 mips_load_const (code, mips_t9, addr);
3755 mips_jalr (code, mips_t9, mips_ra);
3756 mips_nop (code);
3757 mips_break (code, 0xfb);
3758 break;
3760 case OP_START_HANDLER: {
3762 * The START_HANDLER instruction marks the beginning of
3763 * a handler block. It is called using a call
3764 * instruction, so mips_ra contains the return address.
3765 * Since the handler executes in the same stack frame
3766 * as the method itself, we can't use save/restore to
3767 * save the return address. Instead, we save it into
3768 * a dedicated variable.
3770 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3771 g_assert (spvar->inst_basereg != mips_sp);
3772 code = emit_reserve_param_area (cfg, code);
3774 if (mips_is_imm16 (spvar->inst_offset)) {
3775 mips_sw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
3776 } else {
3777 mips_load_const (code, mips_at, spvar->inst_offset);
3778 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
3779 mips_sw (code, mips_ra, mips_at, 0);
3781 break;
3783 case OP_ENDFILTER: {
3784 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3785 g_assert (spvar->inst_basereg != mips_sp);
3786 code = emit_unreserve_param_area (cfg, code);
3788 if (ins->sreg1 != mips_v0)
3789 MIPS_MOVE (code, mips_v0, ins->sreg1);
3790 if (mips_is_imm16 (spvar->inst_offset)) {
3791 mips_lw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
3792 } else {
3793 mips_load_const (code, mips_at, spvar->inst_offset);
3794 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
3795 mips_lw (code, mips_ra, mips_at, 0);
3797 mips_jr (code, mips_ra);
3798 mips_nop (code);
3799 break;
3801 case OP_ENDFINALLY: {
3802 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3803 g_assert (spvar->inst_basereg != mips_sp);
3804 code = emit_unreserve_param_area (cfg, code);
3805 mips_lw (code, mips_t9, spvar->inst_basereg, spvar->inst_offset);
3806 mips_jalr (code, mips_t9, mips_ra);
3807 mips_nop (code);
3808 break;
3810 case OP_CALL_HANDLER:
3811 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3812 mips_lui (code, mips_t9, mips_zero, 0);
3813 mips_addiu (code, mips_t9, mips_t9, 0);
3814 mips_jalr (code, mips_t9, mips_ra);
3815 mips_nop (code);
3816 /*FIXME should it be before the NOP or not? Does MIPS has a delay slot like sparc?*/
3817 mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
3818 break;
3819 case OP_LABEL:
3820 ins->inst_c0 = code - cfg->native_code;
3821 break;
3822 case OP_BR:
3823 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3824 #if LONG_BRANCH
3825 mips_lui (code, mips_at, mips_zero, 0);
3826 mips_addiu (code, mips_at, mips_at, 0);
3827 mips_jr (code, mips_at);
3828 mips_nop (code);
3829 #else
3830 mips_beq (code, mips_zero, mips_zero, 0);
3831 mips_nop (code);
3832 #endif
3833 break;
3834 case OP_BR_REG:
3835 mips_jr (code, ins->sreg1);
3836 mips_nop (code);
3837 break;
3838 case OP_SWITCH: {
3839 int i;
3841 max_len += 4 * GPOINTER_TO_INT (ins->klass);
3842 if (offset > (cfg->code_size - max_len - 16)) {
3843 cfg->code_size += max_len;
3844 cfg->code_size *= 2;
3845 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3846 code = cfg->native_code + offset;
3848 g_assert (ins->sreg1 != -1);
3849 mips_sll (code, mips_at, ins->sreg1, 2);
3850 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS))
3851 MIPS_MOVE (code, mips_t8, mips_ra);
3852 mips_bgezal (code, mips_zero, 1); /* bal */
3853 mips_nop (code);
3854 mips_addu (code, mips_t9, mips_ra, mips_at);
3855 /* Table is 16 or 20 bytes from target of bal above */
3856 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS)) {
3857 MIPS_MOVE (code, mips_ra, mips_t8);
3858 mips_lw (code, mips_t9, mips_t9, 20);
3860 else
3861 mips_lw (code, mips_t9, mips_t9, 16);
3862 mips_jalr (code, mips_t9, mips_t8);
3863 mips_nop (code);
3864 for (i = 0; i < GPOINTER_TO_INT (ins->klass); ++i)
3865 mips_emit32 (code, 0xfefefefe);
3866 break;
3868 case OP_CEQ:
3869 case OP_ICEQ:
3870 mips_addiu (code, ins->dreg, mips_zero, 1);
3871 mips_beq (code, mips_at, mips_zero, 2);
3872 mips_nop (code);
3873 MIPS_MOVE (code, ins->dreg, mips_zero);
3874 break;
3875 case OP_CLT:
3876 case OP_CLT_UN:
3877 case OP_ICLT:
3878 case OP_ICLT_UN:
3879 mips_addiu (code, ins->dreg, mips_zero, 1);
3880 mips_bltz (code, mips_at, 2);
3881 mips_nop (code);
3882 MIPS_MOVE (code, ins->dreg, mips_zero);
3883 break;
3884 case OP_CGT:
3885 case OP_CGT_UN:
3886 case OP_ICGT:
3887 case OP_ICGT_UN:
3888 mips_addiu (code, ins->dreg, mips_zero, 1);
3889 mips_bgtz (code, mips_at, 2);
3890 mips_nop (code);
3891 MIPS_MOVE (code, ins->dreg, mips_zero);
3892 break;
3894 case OP_MIPS_COND_EXC_EQ:
3895 case OP_MIPS_COND_EXC_GE:
3896 case OP_MIPS_COND_EXC_GT:
3897 case OP_MIPS_COND_EXC_LE:
3898 case OP_MIPS_COND_EXC_LT:
3899 case OP_MIPS_COND_EXC_NE_UN:
3900 case OP_MIPS_COND_EXC_GE_UN:
3901 case OP_MIPS_COND_EXC_GT_UN:
3902 case OP_MIPS_COND_EXC_LE_UN:
3903 case OP_MIPS_COND_EXC_LT_UN:
3905 case OP_MIPS_COND_EXC_OV:
3906 case OP_MIPS_COND_EXC_NO:
3907 case OP_MIPS_COND_EXC_C:
3908 case OP_MIPS_COND_EXC_NC:
3910 case OP_MIPS_COND_EXC_IEQ:
3911 case OP_MIPS_COND_EXC_IGE:
3912 case OP_MIPS_COND_EXC_IGT:
3913 case OP_MIPS_COND_EXC_ILE:
3914 case OP_MIPS_COND_EXC_ILT:
3915 case OP_MIPS_COND_EXC_INE_UN:
3916 case OP_MIPS_COND_EXC_IGE_UN:
3917 case OP_MIPS_COND_EXC_IGT_UN:
3918 case OP_MIPS_COND_EXC_ILE_UN:
3919 case OP_MIPS_COND_EXC_ILT_UN:
3921 case OP_MIPS_COND_EXC_IOV:
3922 case OP_MIPS_COND_EXC_INO:
3923 case OP_MIPS_COND_EXC_IC:
3924 case OP_MIPS_COND_EXC_INC: {
3925 guint32 *skip;
3926 guint32 *throw;
3928 /* If the condition is true, raise the exception */
3930 /* need to reverse test to skip around exception raising */
3932 /* For the moment, branch around a branch to avoid reversing
3933 the tests. */
3935 /* Remember, an unpatched branch to 0 branches to the delay slot */
3936 switch (ins->opcode) {
3937 case OP_MIPS_COND_EXC_EQ:
3938 throw = (guint32 *)(void *)code;
3939 mips_beq (code, ins->sreg1, ins->sreg2, 0);
3940 mips_nop (code);
3941 break;
3943 case OP_MIPS_COND_EXC_NE_UN:
3944 throw = (guint32 *)(void *)code;
3945 mips_bne (code, ins->sreg1, ins->sreg2, 0);
3946 mips_nop (code);
3947 break;
3949 case OP_MIPS_COND_EXC_LE_UN:
3950 mips_subu (code, mips_at, ins->sreg1, ins->sreg2);
3951 throw = (guint32 *)(void *)code;
3952 mips_blez (code, mips_at, 0);
3953 mips_nop (code);
3954 break;
3956 case OP_MIPS_COND_EXC_GT:
3957 mips_slt (code, mips_at, ins->sreg2, ins->sreg1);
3958 throw = (guint32 *)(void *)code;
3959 mips_bne (code, mips_at, mips_zero, 0);
3960 mips_nop (code);
3961 break;
3963 case OP_MIPS_COND_EXC_GT_UN:
3964 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
3965 throw = (guint32 *)(void *)code;
3966 mips_bne (code, mips_at, mips_zero, 0);
3967 mips_nop (code);
3968 break;
3970 case OP_MIPS_COND_EXC_LT:
3971 mips_slt (code, mips_at, ins->sreg1, ins->sreg2);
3972 throw = (guint32 *)(void *)code;
3973 mips_bne (code, mips_at, mips_zero, 0);
3974 mips_nop (code);
3975 break;
3977 case OP_MIPS_COND_EXC_LT_UN:
3978 mips_sltu (code, mips_at, ins->sreg1, ins->sreg2);
3979 throw = (guint32 *)(void *)code;
3980 mips_bne (code, mips_at, mips_zero, 0);
3981 mips_nop (code);
3982 break;
3984 default:
3985 /* Not yet implemented */
3986 g_warning ("NYI conditional exception %s\n", mono_inst_name (ins->opcode));
3987 g_assert_not_reached ();
3989 skip = (guint32 *)(void *)code;
3990 mips_beq (code, mips_zero, mips_zero, 0);
3991 mips_nop (code);
3992 mips_patch (throw, (guint32)code);
3993 code = mips_emit_exc_by_name (code, ins->inst_p1);
3994 mips_patch (skip, (guint32)code);
3995 cfg->bb_exit->max_offset += 24;
3996 break;
3998 case OP_MIPS_BEQ:
3999 case OP_MIPS_BNE:
4000 case OP_MIPS_BGEZ:
4001 case OP_MIPS_BGTZ:
4002 case OP_MIPS_BLEZ:
4003 case OP_MIPS_BLTZ:
4004 code = mips_emit_cond_branch (cfg, code, ins->opcode, ins);
4005 break;
4007 /* floating point opcodes */
4008 case OP_R8CONST:
4009 #if 0
4010 if (((guint32)ins->inst_p0) & (1 << 15))
4011 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4012 else
4013 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4014 mips_ldc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4015 #else
4016 mips_load_const (code, mips_at, ins->inst_p0);
4017 mips_lwc1 (code, ins->dreg, mips_at, 4);
4018 mips_lwc1 (code, ins->dreg+1, mips_at, 0);
4019 #endif
4020 break;
4021 case OP_R4CONST:
4022 if (((guint32)ins->inst_p0) & (1 << 15))
4023 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4024 else
4025 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4026 mips_lwc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4027 #if PROMOTE_R4_TO_R8
4028 mips_cvtds (code, ins->dreg, ins->dreg);
4029 #endif
4030 break;
4031 case OP_STORER8_MEMBASE_REG:
4032 if (mips_is_imm16 (ins->inst_offset)) {
4033 #if _MIPS_SIM == _ABIO32
4034 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset+4);
4035 mips_swc1 (code, ins->sreg1+1, ins->inst_destbasereg, ins->inst_offset);
4036 #elif _MIPS_SIM == _ABIN32
4037 mips_sdc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4038 #endif
4039 } else {
4040 mips_load_const (code, mips_at, ins->inst_offset);
4041 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
4042 mips_swc1 (code, ins->sreg1, mips_at, 4);
4043 mips_swc1 (code, ins->sreg1+1, mips_at, 0);
4045 break;
4046 case OP_LOADR8_MEMBASE:
4047 if (mips_is_imm16 (ins->inst_offset)) {
4048 #if _MIPS_SIM == _ABIO32
4049 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset+4);
4050 mips_lwc1 (code, ins->dreg+1, ins->inst_basereg, ins->inst_offset);
4051 #elif _MIPS_SIM == _ABIN32
4052 mips_ldc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4053 #endif
4054 } else {
4055 mips_load_const (code, mips_at, ins->inst_offset);
4056 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
4057 mips_lwc1 (code, ins->dreg, mips_at, 4);
4058 mips_lwc1 (code, ins->dreg+1, mips_at, 0);
4060 break;
4061 case OP_STORER4_MEMBASE_REG:
4062 g_assert (mips_is_imm16 (ins->inst_offset));
4063 #if PROMOTE_R4_TO_R8
4064 /* Need to convert ins->sreg1 to single-precision first */
4065 mips_cvtsd (code, mips_ftemp, ins->sreg1);
4066 #endif
4067 mips_swc1 (code, mips_ftemp, ins->inst_destbasereg, ins->inst_offset);
4068 break;
4069 case OP_MIPS_LWC1:
4070 g_assert (mips_is_imm16 (ins->inst_offset));
4071 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4072 break;
4073 case OP_LOADR4_MEMBASE:
4074 g_assert (mips_is_imm16 (ins->inst_offset));
4075 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4076 #if PROMOTE_R4_TO_R8
4077 /* Convert to double precision in place */
4078 mips_cvtds (code, ins->dreg, ins->dreg);
4079 #endif
4080 break;
4081 case OP_ICONV_TO_R_UN: {
4082 static const guint64 adjust_val = 0x41F0000000000000ULL;
4084 /* convert unsigned int to double */
4085 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4086 mips_bgez (code, ins->sreg1, 5);
4087 mips_cvtdw (code, ins->dreg, mips_ftemp);
4089 mips_load (code, mips_at, (guint32) &adjust_val);
4090 mips_ldc1 (code, mips_ftemp, mips_at, 0);
4091 mips_faddd (code, ins->dreg, ins->dreg, mips_ftemp);
4092 /* target is here */
4093 break;
4095 case OP_ICONV_TO_R4:
4096 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4097 mips_cvtsw (code, ins->dreg, mips_ftemp);
4098 mips_cvtds (code, ins->dreg, ins->dreg);
4099 break;
4100 case OP_ICONV_TO_R8:
4101 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4102 mips_cvtdw (code, ins->dreg, mips_ftemp);
4103 break;
4104 case OP_FCONV_TO_I1:
4105 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4106 break;
4107 case OP_FCONV_TO_U1:
4108 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4109 break;
4110 case OP_FCONV_TO_I2:
4111 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4112 break;
4113 case OP_FCONV_TO_U2:
4114 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4115 break;
4116 case OP_FCONV_TO_I4:
4117 case OP_FCONV_TO_I:
4118 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4119 break;
4120 case OP_FCONV_TO_U4:
4121 case OP_FCONV_TO_U:
4122 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4123 break;
4124 case OP_SQRT:
4125 mips_fsqrtd (code, ins->dreg, ins->sreg1);
4126 break;
4127 case OP_FADD:
4128 mips_faddd (code, ins->dreg, ins->sreg1, ins->sreg2);
4129 break;
4130 case OP_FSUB:
4131 mips_fsubd (code, ins->dreg, ins->sreg1, ins->sreg2);
4132 break;
4133 case OP_FMUL:
4134 mips_fmuld (code, ins->dreg, ins->sreg1, ins->sreg2);
4135 break;
4136 case OP_FDIV:
4137 mips_fdivd (code, ins->dreg, ins->sreg1, ins->sreg2);
4138 break;
4139 case OP_FNEG:
4140 mips_fnegd (code, ins->dreg, ins->sreg1);
4141 break;
4142 case OP_FCEQ:
4143 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
4144 mips_addiu (code, ins->dreg, mips_zero, 1);
4145 mips_fbtrue (code, 2);
4146 mips_nop (code);
4147 MIPS_MOVE (code, ins->dreg, mips_zero);
4148 break;
4149 case OP_FCLT:
4150 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
4151 mips_addiu (code, ins->dreg, mips_zero, 1);
4152 mips_fbtrue (code, 2);
4153 mips_nop (code);
4154 MIPS_MOVE (code, ins->dreg, mips_zero);
4155 break;
4156 case OP_FCLT_UN:
4157 /* Less than, or Unordered */
4158 mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
4159 mips_addiu (code, ins->dreg, mips_zero, 1);
4160 mips_fbtrue (code, 2);
4161 mips_nop (code);
4162 MIPS_MOVE (code, ins->dreg, mips_zero);
4163 break;
4164 case OP_FCGT:
4165 mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
4166 MIPS_MOVE (code, ins->dreg, mips_zero);
4167 mips_fbtrue (code, 2);
4168 mips_nop (code);
4169 mips_addiu (code, ins->dreg, mips_zero, 1);
4170 break;
4171 case OP_FCGT_UN:
4172 /* Greater than, or Unordered */
4173 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
4174 MIPS_MOVE (code, ins->dreg, mips_zero);
4175 mips_fbtrue (code, 2);
4176 mips_nop (code);
4177 mips_addiu (code, ins->dreg, mips_zero, 1);
4178 break;
4179 case OP_MIPS_FBEQ:
4180 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
4181 mips_nop (code);
4182 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4183 mips_fbtrue (code, 0);
4184 mips_nop (code);
4185 break;
4186 case OP_MIPS_FBNE:
4187 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
4188 mips_nop (code);
4189 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4190 mips_fbfalse (code, 0);
4191 mips_nop (code);
4192 break;
4193 case OP_MIPS_FBLT:
4194 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
4195 mips_nop (code);
4196 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4197 mips_fbtrue (code, 0);
4198 mips_nop (code);
4199 break;
4200 case OP_MIPS_FBLT_UN:
4201 mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
4202 mips_nop (code);
4203 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4204 mips_fbtrue (code, 0);
4205 mips_nop (code);
4206 break;
4207 case OP_MIPS_FBGT:
4208 mips_fcmpd (code, MIPS_FPU_LE, ins->sreg1, ins->sreg2);
4209 mips_nop (code);
4210 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4211 mips_fbfalse (code, 0);
4212 mips_nop (code);
4213 break;
4214 case OP_MIPS_FBGT_UN:
4215 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
4216 mips_nop (code);
4217 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4218 mips_fbfalse (code, 0);
4219 mips_nop (code);
4220 break;
4221 case OP_MIPS_FBGE:
4222 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
4223 mips_nop (code);
4224 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4225 mips_fbfalse (code, 0);
4226 mips_nop (code);
4227 break;
4228 case OP_MIPS_FBGE_UN:
4229 mips_fcmpd (code, MIPS_FPU_OLT, ins->sreg1, ins->sreg2);
4230 mips_nop (code);
4231 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4232 mips_fbfalse (code, 0);
4233 mips_nop (code);
4234 break;
4235 case OP_MIPS_FBLE:
4236 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
4237 mips_nop (code);
4238 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4239 mips_fbtrue (code, 0);
4240 mips_nop (code);
4241 break;
4242 case OP_MIPS_FBLE_UN:
4243 mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
4244 mips_nop (code);
4245 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4246 mips_fbtrue (code, 0);
4247 mips_nop (code);
4248 break;
4249 case OP_CKFINITE: {
4250 guint32 *branch_patch;
4252 mips_mfc1 (code, mips_at, ins->sreg1+1);
4253 mips_srl (code, mips_at, mips_at, 16+4);
4254 mips_andi (code, mips_at, mips_at, 2047);
4255 mips_addiu (code, mips_at, mips_at, -2047);
4257 branch_patch = (guint32 *)(void *)code;
4258 mips_bne (code, mips_at, mips_zero, 0);
4259 mips_nop (code);
4261 EMIT_SYSTEM_EXCEPTION_NAME("ArithmeticException");
4262 mips_patch (branch_patch, (guint32)code);
4263 mips_fmovd (code, ins->dreg, ins->sreg1);
4264 break;
4266 case OP_JUMP_TABLE:
4267 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
4268 mips_load (code, ins->dreg, 0x0f0f0f0f);
4269 break;
4272 default:
4273 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4274 g_assert_not_reached ();
4277 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4278 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
4279 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
4280 g_assert_not_reached ();
4283 cpos += max_len;
4285 last_ins = ins;
4286 last_offset = offset;
4289 cfg->code_len = code - cfg->native_code;
4292 void
4293 mono_arch_register_lowlevel_calls (void)
4297 void
4298 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
4300 MonoJumpInfo *patch_info;
4302 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4303 unsigned char *ip = patch_info->ip.i + code;
4304 const unsigned char *target = NULL;
4306 switch (patch_info->type) {
4307 case MONO_PATCH_INFO_IP:
4308 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)ip);
4309 continue;
4310 case MONO_PATCH_INFO_SWITCH: {
4311 gpointer *table = (gpointer *)patch_info->data.table->table;
4312 int i;
4314 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)table);
4316 for (i = 0; i < patch_info->data.table->table_size; i++) {
4317 table [i] = (int)patch_info->data.table->table [i] + code;
4319 continue;
4321 case MONO_PATCH_INFO_METHODCONST:
4322 case MONO_PATCH_INFO_CLASS:
4323 case MONO_PATCH_INFO_IMAGE:
4324 case MONO_PATCH_INFO_FIELD:
4325 case MONO_PATCH_INFO_VTABLE:
4326 case MONO_PATCH_INFO_IID:
4327 case MONO_PATCH_INFO_SFLDA:
4328 case MONO_PATCH_INFO_LDSTR:
4329 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4330 case MONO_PATCH_INFO_LDTOKEN:
4331 case MONO_PATCH_INFO_R4:
4332 case MONO_PATCH_INFO_R8:
4333 /* from OP_AOTCONST : lui + addiu */
4334 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4335 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)target);
4336 continue;
4337 #if 0
4338 case MONO_PATCH_INFO_EXC_NAME:
4339 g_assert_not_reached ();
4340 *((gconstpointer *)(void *)(ip + 1)) = patch_info->data.name;
4341 continue;
4342 #endif
4343 case MONO_PATCH_INFO_NONE:
4344 /* everything is dealt with at epilog output time */
4345 continue;
4346 default:
4347 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4348 mips_patch ((guint32 *)(void *)ip, (guint32)target);
4349 break;
4354 #if 0
4355 static
4356 void
4357 mono_trace_lmf_prolog (MonoLMF *new_lmf)
4361 static
4362 void
4363 mono_trace_lmf_epilog (MonoLMF *old_lmf)
4366 #endif
4369 * Allow tracing to work with this interface (with an optional argument)
4371 * This code is expected to be inserted just after the 'real' prolog code,
4372 * and before the first basic block. We need to allocate a 2nd, temporary
4373 * stack frame so that we can preserve f12-f15 as well as a0-a3.
4376 void*
4377 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4379 guchar *code = p;
4380 int offset = cfg->arch.tracing_offset;
4382 mips_nop (code);
4383 mips_nop (code);
4384 mips_nop (code);
4386 /* For N32, need to know for each stack slot if it's an integer
4387 * or float argument, and save/restore the appropriate register
4389 MIPS_SW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4390 MIPS_SW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4391 MIPS_SW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4392 MIPS_SW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4393 #if _MIPS_SIM == _ABIN32
4394 MIPS_SW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4395 MIPS_SW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4396 MIPS_SW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4397 MIPS_SW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4398 #endif
4400 mips_load_const (code, mips_a0, cfg->method);
4401 mips_addiu (code, mips_a1, mips_sp, offset);
4402 mips_load_const (code, mips_t9, func);
4403 mips_jalr (code, mips_t9, mips_ra);
4404 mips_nop (code);
4406 MIPS_LW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4407 MIPS_LW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4408 MIPS_LW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4409 MIPS_LW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4410 #if _MIPS_SIM == _ABIN32
4411 MIPS_LW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4412 MIPS_LW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4413 MIPS_LW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4414 MIPS_LW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4415 #endif
4417 mips_nop (code);
4418 mips_nop (code);
4419 mips_nop (code);
4420 return code;
4423 void
4424 mips_adjust_stackframe(MonoCompile *cfg)
4426 MonoBasicBlock *bb;
4427 int delta, threshold, i;
4428 MonoMethodSignature *sig;
4429 int ra_offset;
4431 if (cfg->stack_offset == cfg->arch.local_alloc_offset)
4432 return;
4434 /* adjust cfg->stack_offset for account for down-spilling */
4435 cfg->stack_offset += SIZEOF_REGISTER;
4437 /* re-align cfg->stack_offset if needed (due to var spilling) */
4438 cfg->stack_offset = (cfg->stack_offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
4439 delta = cfg->stack_offset - cfg->arch.local_alloc_offset;
4440 if (cfg->verbose_level > 2) {
4441 g_print ("mips_adjust_stackframe:\n");
4442 g_print ("\tspillvars allocated 0x%x -> 0x%x\n", cfg->arch.local_alloc_offset, cfg->stack_offset);
4444 threshold = cfg->arch.local_alloc_offset;
4445 ra_offset = cfg->stack_offset - sizeof(gpointer);
4446 if (cfg->verbose_level > 2) {
4447 g_print ("\tra_offset %d/0x%x delta %d/0x%x\n", ra_offset, ra_offset, delta, delta);
4450 sig = mono_method_signature (cfg->method);
4451 if (sig && sig->ret && MONO_TYPE_ISSTRUCT (sig->ret)) {
4452 cfg->vret_addr->inst_offset += delta;
4454 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4455 MonoInst *inst = cfg->args [i];
4457 inst->inst_offset += delta;
4461 * loads and stores based off the frame reg that (used to) lie
4462 * above the spill var area need to be increased by 'delta'
4463 * to make room for the spill vars.
4465 /* Need to find loads and stores to adjust that
4466 * are above where the spillvars were inserted, but
4467 * which are not the spillvar references themselves.
4469 * Idea - since all offsets from fp are positive, make
4470 * spillvar offsets negative to begin with so we can spot
4471 * them here.
4474 #if 1
4475 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4476 int ins_cnt = 0;
4477 MonoInst *ins;
4479 if (cfg->verbose_level > 2) {
4480 g_print ("BASIC BLOCK %d:\n", bb->block_num);
4482 MONO_BB_FOR_EACH_INS (bb, ins) {
4483 int adj_c0 = 0;
4484 int adj_imm = 0;
4486 if (cfg->verbose_level > 2) {
4487 mono_print_ins_index (ins_cnt, ins);
4489 if (MONO_IS_LOAD_MEMBASE(ins) && (ins->inst_basereg == mips_fp))
4490 adj_c0 = 1;
4491 if (MONO_IS_STORE_MEMBASE(ins) && (ins->dreg == mips_fp))
4492 adj_c0 = 1;
4493 /* The following two catch FP spills */
4494 if (MONO_IS_LOAD_MEMBASE(ins) && (ins->inst_basereg == mips_sp))
4495 adj_c0 = 1;
4496 if (MONO_IS_STORE_MEMBASE(ins) && (ins->dreg == mips_sp))
4497 adj_c0 = 1;
4498 if (((ins->opcode == OP_ADD_IMM) || (ins->opcode == OP_IADD_IMM)) && (ins->sreg1 == mips_fp))
4499 adj_imm = 1;
4500 if (adj_c0) {
4501 if (ins->inst_c0 >= threshold) {
4502 ins->inst_c0 += delta;
4503 if (cfg->verbose_level > 2) {
4504 g_print ("adj");
4505 mono_print_ins_index (ins_cnt, ins);
4508 else if (ins->inst_c0 < 0) {
4509 ins->inst_c0 = - ins->inst_c0 - 4;
4510 if (cfg->verbose_level > 2) {
4511 g_print ("spill");
4512 mono_print_ins_index (ins_cnt, ins);
4515 g_assert (ins->inst_c0 != ra_offset);
4517 if (adj_imm) {
4518 if (ins->inst_imm >= threshold) {
4519 ins->inst_imm += delta;
4520 if (cfg->verbose_level > 2) {
4521 g_print ("adj");
4522 mono_print_ins_index (ins_cnt, ins);
4525 g_assert (ins->inst_c0 != ra_offset);
4528 ++ins_cnt;
4531 #endif
4535 * Stack frame layout:
4537 * ------------------- sp + cfg->stack_usage + cfg->param_area
4538 * param area incoming
4539 * ------------------- sp + cfg->stack_usage + MIPS_STACK_PARAM_OFFSET
4540 * a0-a3 incoming
4541 * ------------------- sp + cfg->stack_usage
4542 * ra
4543 * ------------------- sp + cfg->stack_usage-4
4544 * spilled regs
4545 * ------------------- sp +
4546 * MonoLMF structure optional
4547 * ------------------- sp + cfg->arch.lmf_offset
4548 * saved registers s0-s8
4549 * ------------------- sp + cfg->arch.iregs_offset
4550 * locals
4551 * ------------------- sp + cfg->param_area
4552 * param area outgoing
4553 * ------------------- sp + MIPS_STACK_PARAM_OFFSET
4554 * a0-a3 outgoing
4555 * ------------------- sp
4556 * red zone
4558 guint8 *
4559 mono_arch_emit_prolog (MonoCompile *cfg)
4561 MonoMethod *method = cfg->method;
4562 MonoMethodSignature *sig;
4563 MonoInst *inst;
4564 int alloc_size, pos, i;
4565 guint8 *code;
4566 CallInfo *cinfo;
4567 int tracing = 0;
4568 guint32 iregs_to_save = 0;
4569 #if SAVE_FP_REGS
4570 guint32 fregs_to_save = 0;
4571 #endif
4572 #if SAVE_LMF
4573 /* lmf_offset is the offset of the LMF from our stack pointer. */
4574 guint32 lmf_offset = cfg->arch.lmf_offset;
4575 #endif
4577 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4578 tracing = 1;
4580 if (tracing)
4581 cfg->flags |= MONO_CFG_HAS_CALLS;
4583 sig = mono_method_signature (method);
4584 cfg->code_size = 768 + sig->param_count * 20;
4585 code = cfg->native_code = g_malloc (cfg->code_size);
4587 if (tracing) {
4588 #if _MIPS_SIM == _ABIO32
4589 cfg->arch.tracing_offset = cfg->stack_offset;
4590 #elif _MIPS_SIM == _ABIN32
4591 /* no stack slots by default for argument regs, reserve a special block */
4592 cfg->arch.tracing_offset = cfg->stack_offset;
4593 cfg->stack_offset += 8 * SIZEOF_REGISTER;
4594 #endif
4597 /* adjust stackframe assignments for spillvars if needed */
4598 mips_adjust_stackframe (cfg);
4600 /* stack_offset should not be changed here. */
4601 alloc_size = cfg->stack_offset;
4602 cfg->stack_usage = alloc_size;
4604 #if SAVE_ALL_REGS
4605 iregs_to_save = MONO_ARCH_CALLEE_SAVED_REGS;
4606 #else
4607 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
4608 #endif
4609 #if SAVE_FP_REGS
4610 #if 0
4611 fregs_to_save = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
4612 #else
4613 fregs_to_save = MONO_ARCH_CALLEE_SAVED_FREGS;
4614 fregs_to_save |= (fregs_to_save << 1);
4615 #endif
4616 #endif
4617 if (alloc_size) {
4618 if (mips_is_imm16 (-alloc_size)) {
4619 mips_addiu (code, mips_sp, mips_sp, -alloc_size);
4620 } else {
4621 mips_load_const (code, mips_at, -alloc_size);
4622 mips_addu (code, mips_sp, mips_sp, mips_at);
4626 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA)
4627 mips_sw (code, mips_ra, mips_sp, alloc_size + MIPS_RET_ADDR_OFFSET);
4629 /* XXX - optimize this later to not save all regs if LMF constructed */
4631 if (iregs_to_save) {
4632 /* save used registers in own stack frame (at pos) */
4633 pos = cfg->arch.iregs_offset;
4634 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
4635 if (iregs_to_save & (1 << i)) {
4636 g_assert (pos < cfg->stack_usage - sizeof(gpointer));
4637 MIPS_SW (code, i, mips_sp, pos);
4638 pos += SIZEOF_REGISTER;
4642 #if SAVE_LMF
4643 if (method->save_lmf) {
4644 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
4645 MIPS_SW (code, i, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[i]));
4648 #endif
4650 #if SAVE_FP_REGS
4651 /* Save float registers */
4652 if (fregs_to_save) {
4653 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
4654 if (fregs_to_save & (1 << i)) {
4655 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
4656 mips_swc1 (code, i, mips_sp, pos);
4657 pos += sizeof (gulong);
4661 #if SAVE_LMF
4662 if (method->save_lmf) {
4663 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
4664 mips_swc1 (code, i, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, fregs[i]));
4667 #endif
4668 #endif
4669 if (cfg->frame_reg != mips_sp) {
4670 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
4671 #if SAVE_LMF
4672 if (method->save_lmf)
4673 MIPS_SW (code, cfg->frame_reg, mips_sp,
4674 lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[cfg->frame_reg]));
4675 #endif
4678 /* Do instrumentation before assigning regvars to registers. Because they may be assigned
4679 * to the t* registers, which would be clobbered by the instrumentation calls.
4681 if (tracing) {
4682 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
4686 /* load arguments allocated to register from the stack */
4687 pos = 0;
4689 cinfo = calculate_sizes (sig, sig->pinvoke);
4691 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
4692 ArgInfo *ainfo = &cinfo->ret;
4693 inst = cfg->vret_addr;
4694 if (inst->opcode == OP_REGVAR)
4695 MIPS_MOVE (code, inst->dreg, ainfo->reg);
4696 else if (mips_is_imm16 (inst->inst_offset)) {
4697 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4698 } else {
4699 mips_load_const (code, mips_at, inst->inst_offset);
4700 mips_addu (code, mips_at, mips_at, inst->inst_basereg);
4701 mips_sw (code, ainfo->reg, mips_at, 0);
4704 /* Keep this in sync with emit_load_volatile_arguments */
4705 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4706 ArgInfo *ainfo = cinfo->args + i;
4707 inst = cfg->args [pos];
4709 if (cfg->verbose_level > 2)
4710 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
4711 if (inst->opcode == OP_REGVAR) {
4712 /* Argument ends up in a register */
4713 if (ainfo->regtype == RegTypeGeneral)
4714 MIPS_MOVE (code, inst->dreg, ainfo->reg);
4715 else if (ainfo->regtype == RegTypeFP) {
4716 g_assert_not_reached();
4717 #if 0
4718 ppc_fmr (code, inst->dreg, ainfo->reg);
4719 #endif
4721 else if (ainfo->regtype == RegTypeBase) {
4722 mips_lw (code, inst->dreg, mips_sp, cfg->stack_usage + ainfo->offset);
4723 } else
4724 g_assert_not_reached ();
4726 if (cfg->verbose_level > 2)
4727 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
4728 } else {
4729 /* Argument ends up on the stack */
4730 if (ainfo->regtype == RegTypeGeneral) {
4731 /* Incoming parameters should be above this frame */
4732 if (cfg->verbose_level > 2)
4733 g_print ("stack slot at %d of %d\n", inst->inst_offset, alloc_size);
4734 /* g_assert (inst->inst_offset >= alloc_size); */
4735 g_assert (mips_is_imm16 (inst->inst_offset));
4736 switch (ainfo->size) {
4737 case 1:
4738 mips_sb (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4739 break;
4740 case 2:
4741 mips_sh (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4742 break;
4743 case 0: /* XXX */
4744 case 4:
4745 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4746 break;
4747 case 8:
4748 #if (SIZEOF_REGISTER == 4)
4749 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4750 mips_sw (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + 4);
4751 #elif (SIZEOF_REGISTER == 8)
4752 mips_sd (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4753 #endif
4754 break;
4755 default:
4756 g_assert_not_reached ();
4757 break;
4759 } else if (ainfo->regtype == RegTypeBase) {
4761 * Argument comes in on the stack, and ends up on the stack
4762 * 1 and 2 byte args are passed as 32-bit quantities, but used as
4763 * 8 and 16 bit quantities. Shorten them in place.
4765 g_assert (mips_is_imm16 (inst->inst_offset));
4766 switch (ainfo->size) {
4767 case 1:
4768 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
4769 mips_sb (code, mips_at, inst->inst_basereg, inst->inst_offset);
4770 break;
4771 case 2:
4772 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
4773 mips_sh (code, mips_at, inst->inst_basereg, inst->inst_offset);
4774 break;
4775 case 0: /* XXX */
4776 case 4:
4777 case 8:
4778 break;
4779 default:
4780 g_assert_not_reached ();
4782 } else if (ainfo->regtype == RegTypeFP) {
4783 g_assert (mips_is_imm16 (inst->inst_offset));
4784 if (ainfo->size == 8) {
4785 #if _MIPS_SIM == _ABIO32
4786 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset+4);
4787 mips_swc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset);
4788 #elif _MIPS_SIM == _ABIN32
4789 mips_sdc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4790 #endif
4792 else if (ainfo->size == 4)
4793 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4794 else
4795 g_assert_not_reached ();
4796 } else if (ainfo->regtype == RegTypeStructByVal) {
4797 int i;
4798 int doffset = inst->inst_offset;
4800 g_assert (mips_is_imm16 (inst->inst_offset));
4801 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
4802 /* Push the argument registers into their stack slots */
4803 for (i = 0; i < ainfo->size; ++i) {
4804 MIPS_SW (code, ainfo->reg + i, inst->inst_basereg, doffset);
4805 doffset += SIZEOF_REGISTER;
4807 } else if (ainfo->regtype == RegTypeStructByAddr) {
4808 g_assert (mips_is_imm16 (inst->inst_offset));
4809 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
4810 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
4811 } else
4812 g_assert_not_reached ();
4814 pos++;
4817 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
4818 mips_load_const (code, mips_a0, cfg->domain);
4819 mips_load_const (code, mips_t9, (gpointer)mono_jit_thread_attach);
4820 mips_jalr (code, mips_t9, mips_ra);
4821 mips_nop (code);
4824 #if SAVE_LMF
4825 if (method->save_lmf) {
4826 mips_load_const (code, mips_at, MIPS_LMF_MAGIC1);
4827 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, magic));
4829 if (lmf_pthread_key != -1) {
4830 g_assert_not_reached();
4831 #if 0
4832 emit_tls_access (code, mips_temp, lmf_pthread_key);
4833 #endif
4834 if (G_STRUCT_OFFSET (MonoJitTlsData, lmf))
4835 mips_addiu (code, mips_a0, mips_temp, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
4836 } else {
4837 #if 0
4838 mips_addiu (code, mips_a0, mips_sp, lmf_offset);
4839 mips_load_const (code, mips_t9, (gpointer)mono_trace_lmf_prolog);
4840 mips_jalr (code, mips_t9, mips_ra);
4841 mips_nop (code);
4842 #endif
4843 /* This can/will clobber the a0-a3 registers */
4844 mips_load_const (code, mips_t9, (gpointer)mono_get_lmf_addr);
4845 mips_jalr (code, mips_t9, mips_ra);
4846 mips_nop (code);
4849 /* mips_v0 is the result from mono_get_lmf_addr () (MonoLMF **) */
4850 mips_sw (code, mips_v0, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
4851 /* new_lmf->previous_lmf = *lmf_addr */
4852 mips_lw (code, mips_at, mips_v0, 0);
4853 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
4854 /* *(lmf_addr) = sp + lmf_offset */
4855 mips_addiu (code, mips_at, mips_sp, lmf_offset);
4856 mips_sw (code, mips_at, mips_v0, 0);
4858 /* save method info */
4859 mips_load_const (code, mips_at, method);
4860 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, method));
4861 MIPS_SW (code, mips_sp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, ebp));
4863 /* save the current IP */
4864 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
4865 mips_load_const (code, mips_at, 0x01010101);
4866 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, eip));
4868 #endif
4870 cfg->code_len = code - cfg->native_code;
4871 g_assert (cfg->code_len < cfg->code_size);
4872 g_free (cinfo);
4874 return code;
4877 enum {
4878 SAVE_NONE,
4879 SAVE_STRUCT,
4880 SAVE_ONE,
4881 SAVE_TWO,
4882 SAVE_FP
4885 void*
4886 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
4888 guchar *code = p;
4889 int save_mode = SAVE_NONE;
4890 int offset;
4891 MonoMethod *method = cfg->method;
4892 int rtype = mono_type_get_underlying_type (mono_method_signature (method)->ret)->type;
4893 int save_offset = MIPS_STACK_PARAM_OFFSET;
4895 g_assert ((save_offset & (MIPS_STACK_ALIGNMENT-1)) == 0);
4897 offset = code - cfg->native_code;
4898 /* we need about 16 instructions */
4899 if (offset > (cfg->code_size - 16 * 4)) {
4900 cfg->code_size *= 2;
4901 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4902 code = cfg->native_code + offset;
4904 mips_nop (code);
4905 mips_nop (code);
4906 switch (rtype) {
4907 case MONO_TYPE_VOID:
4908 /* special case string .ctor icall */
4909 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
4910 save_mode = SAVE_ONE;
4911 else
4912 save_mode = SAVE_NONE;
4913 break;
4914 case MONO_TYPE_R4:
4915 case MONO_TYPE_R8:
4916 save_mode = SAVE_FP;
4917 break;
4918 case MONO_TYPE_VALUETYPE:
4919 save_mode = SAVE_STRUCT;
4920 break;
4921 case MONO_TYPE_I8:
4922 case MONO_TYPE_U8:
4923 #if SIZEOF_REGISTER == 4
4924 save_mode = SAVE_TWO;
4925 #elif SIZEOF_REGISTER == 8
4926 save_mode = SAVE_ONE;
4927 #endif
4928 break;
4929 default:
4930 save_mode = SAVE_ONE;
4931 break;
4934 mips_addiu (code, mips_sp, mips_sp, -32);
4935 switch (save_mode) {
4936 case SAVE_TWO:
4937 mips_sw (code, mips_v0, mips_sp, save_offset);
4938 mips_sw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
4939 if (enable_arguments) {
4940 MIPS_MOVE (code, mips_a1, mips_v0);
4941 MIPS_MOVE (code, mips_a2, mips_v1);
4943 break;
4944 case SAVE_ONE:
4945 MIPS_SW (code, mips_v0, mips_sp, save_offset);
4946 if (enable_arguments) {
4947 MIPS_MOVE (code, mips_a1, mips_v0);
4949 break;
4950 case SAVE_FP:
4951 mips_sdc1 (code, mips_f0, mips_sp, save_offset);
4952 mips_ldc1 (code, mips_f12, mips_sp, save_offset);
4953 mips_lw (code, mips_a0, mips_sp, save_offset);
4954 mips_lw (code, mips_a1, mips_sp, save_offset + SIZEOF_REGISTER);
4955 break;
4956 case SAVE_STRUCT:
4957 case SAVE_NONE:
4958 default:
4959 break;
4961 mips_load_const (code, mips_a0, cfg->method);
4962 mips_load_const (code, mips_t9, func);
4963 mips_jalr (code, mips_t9, mips_ra);
4964 mips_nop (code);
4966 switch (save_mode) {
4967 case SAVE_TWO:
4968 mips_lw (code, mips_v0, mips_sp, save_offset);
4969 mips_lw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
4970 break;
4971 case SAVE_ONE:
4972 MIPS_LW (code, mips_v0, mips_sp, save_offset);
4973 break;
4974 case SAVE_FP:
4975 mips_ldc1 (code, mips_f0, mips_sp, save_offset);
4976 break;
4977 case SAVE_STRUCT:
4978 case SAVE_NONE:
4979 default:
4980 break;
4982 mips_addiu (code, mips_sp, mips_sp, 32);
4983 mips_nop (code);
4984 mips_nop (code);
4985 return code;
4988 guint8 *
4989 mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code)
4991 MonoMethod *method = cfg->method;
4992 int pos = 0, i;
4993 int max_epilog_size = 16 + 20*4;
4994 guint32 iregs_to_restore;
4995 #if SAVE_FP_REGS
4996 guint32 fregs_to_restore;
4997 #endif
4999 #if SAVE_LMF
5000 if (cfg->method->save_lmf)
5001 max_epilog_size += 128;
5002 #endif
5004 if (mono_jit_trace_calls != NULL)
5005 max_epilog_size += 50;
5007 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5008 max_epilog_size += 50;
5010 if (code)
5011 pos = code - cfg->native_code;
5012 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5013 cfg->code_size *= 2;
5014 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5015 mono_jit_stats.code_reallocs++;
5019 * Keep in sync with OP_JMP
5021 if (code)
5022 code = cfg->native_code + pos;
5023 else
5024 code = cfg->native_code + cfg->code_len;
5026 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5027 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5029 pos = cfg->arch.iregs_offset;
5030 if (cfg->frame_reg != mips_sp) {
5031 MIPS_MOVE (code, mips_sp, cfg->frame_reg);
5033 #if SAVE_ALL_REGS
5034 iregs_to_restore = MONO_ARCH_CALLEE_SAVED_REGS;
5035 #else
5036 iregs_to_restore = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
5037 #endif
5038 if (iregs_to_restore) {
5039 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5040 if (iregs_to_restore & (1 << i)) {
5041 MIPS_LW (code, i, mips_sp, pos);
5042 pos += SIZEOF_REGISTER;
5047 #if SAVE_FP_REGS
5048 #if 0
5049 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
5050 #else
5051 fregs_to_restore = MONO_ARCH_CALLEE_SAVED_FREGS;
5052 fregs_to_restore |= (fregs_to_restore << 1);
5053 #endif
5054 if (fregs_to_restore) {
5055 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5056 if (fregs_to_restore & (1 << i)) {
5057 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
5058 mips_lwc1 (code, i, mips_sp, pos);
5059 pos += FREG_SIZE
5063 #endif
5064 #if SAVE_LMF
5065 /* Unlink the LMF if necessary */
5066 if (method->save_lmf) {
5067 int lmf_offset = cfg->arch.lmf_offset;
5069 /* t0 = current_lmf->previous_lmf */
5070 mips_lw (code, mips_temp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5071 /* t1 = lmf_addr */
5072 mips_lw (code, mips_t1, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5073 /* (*lmf_addr) = previous_lmf */
5074 mips_sw (code, mips_temp, mips_t1, 0);
5076 #endif
5077 #if 0
5078 /* Restore the fp */
5079 mips_lw (code, mips_fp, mips_sp, cfg->stack_usage + MIPS_FP_ADDR_OFFSET);
5080 #endif
5081 /* Correct the stack pointer */
5082 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA)
5083 mips_lw (code, mips_ra, mips_sp, cfg->stack_usage + MIPS_RET_ADDR_OFFSET);
5084 mips_addiu (code, mips_sp, mips_sp, cfg->stack_usage);
5086 /* Caller will emit either return or tail-call sequence */
5088 cfg->code_len = code - cfg->native_code;
5090 g_assert (cfg->code_len < cfg->code_size);
5091 return (code);
5094 void
5095 mono_arch_emit_epilog (MonoCompile *cfg)
5097 guint8 *code;
5099 code = mono_arch_emit_epilog_sub (cfg, NULL);
5101 mips_jr (code, mips_ra);
5102 mips_nop (code);
5104 cfg->code_len = code - cfg->native_code;
5106 g_assert (cfg->code_len < cfg->code_size);
5109 /* remove once throw_exception_by_name is eliminated */
5110 #if 0
5111 static int
5112 exception_id_by_name (const char *name)
5114 if (strcmp (name, "IndexOutOfRangeException") == 0)
5115 return MONO_EXC_INDEX_OUT_OF_RANGE;
5116 if (strcmp (name, "OverflowException") == 0)
5117 return MONO_EXC_OVERFLOW;
5118 if (strcmp (name, "ArithmeticException") == 0)
5119 return MONO_EXC_ARITHMETIC;
5120 if (strcmp (name, "DivideByZeroException") == 0)
5121 return MONO_EXC_DIVIDE_BY_ZERO;
5122 if (strcmp (name, "InvalidCastException") == 0)
5123 return MONO_EXC_INVALID_CAST;
5124 if (strcmp (name, "NullReferenceException") == 0)
5125 return MONO_EXC_NULL_REF;
5126 if (strcmp (name, "ArrayTypeMismatchException") == 0)
5127 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5128 g_error ("Unknown intrinsic exception %s\n", name);
5129 return 0;
5131 #endif
5133 void
5134 mono_arch_emit_exceptions (MonoCompile *cfg)
5136 #if 0
5137 MonoJumpInfo *patch_info;
5138 int i;
5139 guint8 *code;
5140 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
5141 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
5142 int max_epilog_size = 50;
5144 /* count the number of exception infos */
5147 * make sure we have enough space for exceptions
5148 * 24 is the simulated call to throw_exception_by_name
5150 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5151 #if 0
5152 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5153 i = exception_id_by_name (patch_info->data.target);
5154 g_assert (i < MONO_EXC_INTRINS_NUM);
5155 if (!exc_throw_found [i]) {
5156 max_epilog_size += 12;
5157 exc_throw_found [i] = TRUE;
5160 #endif
5163 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5164 cfg->code_size *= 2;
5165 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5166 mono_jit_stats.code_reallocs++;
5169 code = cfg->native_code + cfg->code_len;
5171 /* add code to raise exceptions */
5172 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5173 switch (patch_info->type) {
5174 case MONO_PATCH_INFO_EXC: {
5175 #if 0
5176 //unsigned char *ip = patch_info->ip.i + cfg->native_code;
5178 i = exception_id_by_name (patch_info->data.target);
5179 g_assert (i >= 0 && i < MONO_EXC_INTRINS_NUM);
5180 if (!exc_throw_pos [i]) {
5181 guint32 addr;
5183 exc_throw_pos [i] = code;
5184 //g_print ("exc: writing stub at %p\n", code);
5185 mips_load_const (code, mips_a0, patch_info->data.target);
5186 addr = (guint32) mono_arch_get_throw_exception_by_name ();
5187 mips_load_const (code, mips_t9, addr);
5188 mips_jr (code, mips_t9);
5189 mips_nop (code);
5191 //g_print ("exc: patch %p to %p\n", ip, exc_throw_pos[i]);
5193 /* Turn into a Relative patch, pointing at code stub */
5194 patch_info->type = MONO_PATCH_INFO_METHOD_REL;
5195 patch_info->data.offset = exc_throw_pos[i] - cfg->native_code;
5196 #else
5197 g_assert_not_reached();
5198 #endif
5199 break;
5201 default:
5202 /* do nothing */
5203 break;
5207 cfg->code_len = code - cfg->native_code;
5209 g_assert (cfg->code_len < cfg->code_size);
5210 #endif
5214 * Thread local storage support
5216 static void
5217 setup_tls_access (void)
5219 guint32 ptk;
5220 //guint32 *ins, *code;
5222 if (tls_mode == TLS_MODE_FAILED)
5223 return;
5225 if (g_getenv ("MONO_NO_TLS")) {
5226 tls_mode = TLS_MODE_FAILED;
5227 return;
5230 if (tls_mode == TLS_MODE_DETECT) {
5231 /* XXX */
5232 tls_mode = TLS_MODE_FAILED;
5233 return;
5234 #if 0
5236 ins = (guint32*)pthread_getspecific;
5237 /* uncond branch to the real method */
5238 if ((*ins >> 26) == 18) {
5239 gint32 val;
5240 val = (*ins & ~3) << 6;
5241 val >>= 6;
5242 if (*ins & 2) {
5243 /* absolute */
5244 ins = (guint32*)val;
5245 } else {
5246 ins = (guint32*) ((char*)ins + val);
5249 code = &cmplwi_1023;
5250 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
5251 code = &li_0x48;
5252 ppc_li (code, ppc_r4, 0x48);
5253 code = &blr_ins;
5254 ppc_blr (code);
5255 if (*ins == cmplwi_1023) {
5256 int found_lwz_284 = 0;
5257 for (ptk = 0; ptk < 20; ++ptk) {
5258 ++ins;
5259 if (!*ins || *ins == blr_ins)
5260 break;
5261 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
5262 found_lwz_284 = 1;
5263 break;
5266 if (!found_lwz_284) {
5267 tls_mode = TLS_MODE_FAILED;
5268 return;
5270 tls_mode = TLS_MODE_LTHREADS;
5271 } else if (*ins == li_0x48) {
5272 ++ins;
5273 /* uncond branch to the real method */
5274 if ((*ins >> 26) == 18) {
5275 gint32 val;
5276 val = (*ins & ~3) << 6;
5277 val >>= 6;
5278 if (*ins & 2) {
5279 /* absolute */
5280 ins = (guint32*)val;
5281 } else {
5282 ins = (guint32*) ((char*)ins + val);
5284 code = &val;
5285 ppc_li (code, ppc_r0, 0x7FF2);
5286 if (ins [1] == val) {
5287 /* Darwin on G4, implement */
5288 tls_mode = TLS_MODE_FAILED;
5289 return;
5290 } else {
5291 code = &val;
5292 ppc_mfspr (code, ppc_r3, 104);
5293 if (ins [1] != val) {
5294 tls_mode = TLS_MODE_FAILED;
5295 return;
5297 tls_mode = TLS_MODE_DARWIN_G5;
5299 } else {
5300 tls_mode = TLS_MODE_FAILED;
5301 return;
5303 } else {
5304 tls_mode = TLS_MODE_FAILED;
5305 return;
5307 #endif
5309 if (monodomain_key == -1) {
5310 ptk = mono_domain_get_tls_key ();
5311 if (ptk < 1024) {
5312 ptk = mono_pthread_key_for_tls (ptk);
5313 if (ptk < 1024) {
5314 monodomain_key = ptk;
5318 if (lmf_pthread_key == -1) {
5319 ptk = mono_pthread_key_for_tls (mono_jit_tls_id);
5320 if (ptk < 1024) {
5321 /*g_print ("MonoLMF at: %d\n", ptk);*/
5322 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
5323 init_tls_failed = 1;
5324 return;
5326 lmf_pthread_key = ptk;
5329 if (monothread_key == -1) {
5330 ptk = mono_thread_get_tls_key ();
5331 if (ptk < 1024) {
5332 ptk = mono_pthread_key_for_tls (ptk);
5333 if (ptk < 1024) {
5334 monothread_key = ptk;
5335 /*g_print ("thread inited: %d\n", ptk);*/
5337 } else {
5338 /*g_print ("thread not inited yet %d\n", ptk);*/
5343 void
5344 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
5346 setup_tls_access ();
5349 void
5350 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5354 void
5355 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
5357 int this_dreg = mips_a0;
5359 if (vt_reg != -1)
5360 this_dreg = mips_a1;
5362 /* add the this argument */
5363 if (this_reg != -1) {
5364 MonoInst *this;
5365 MONO_INST_NEW (cfg, this, OP_MOVE);
5366 this->type = this_type;
5367 this->sreg1 = this_reg;
5368 this->dreg = mono_alloc_ireg (cfg);
5369 mono_bblock_add_inst (cfg->cbb, this);
5370 mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE);
5373 if (vt_reg != -1) {
5374 MonoInst *vtarg;
5375 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
5376 vtarg->type = STACK_MP;
5377 vtarg->sreg1 = vt_reg;
5378 vtarg->dreg = mono_alloc_ireg (cfg);
5379 mono_bblock_add_inst (cfg->cbb, vtarg);
5380 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, mips_a0, FALSE);
5384 MonoInst*
5385 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5387 MonoInst *ins = NULL;
5389 return ins;
5392 MonoInst*
5393 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5395 return NULL;
5398 gboolean
5399 mono_arch_print_tree (MonoInst *tree, int arity)
5401 return 0;
5404 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
5406 MonoInst* ins;
5408 setup_tls_access ();
5409 if (monodomain_key == -1)
5410 return NULL;
5412 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5413 ins->inst_offset = monodomain_key;
5414 return ins;
5417 gpointer
5418 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5420 /* FIXME: implement */
5421 g_assert_not_reached ();
5424 #ifdef MONO_ARCH_HAVE_IMT
5426 #define CMP_SIZE 12
5427 #define BR_SIZE 4
5428 #define JUMP_IMM_SIZE 12
5429 #define JUMP_IMM32_SIZE 16
5430 #define ENABLE_WRONG_METHOD_CHECK 0
5433 * LOCKING: called with the domain lock held
5435 gpointer
5436 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5437 gpointer fail_tramp)
5439 NOT_IMPLEMENTED;
5440 #if 0
5441 int i;
5442 int size = 0;
5443 guint8 *code, *start;
5445 for (i = 0; i < count; ++i) {
5446 MonoIMTCheckItem *item = imt_entries [i];
5447 if (item->is_equals) {
5448 if (item->check_target_idx) {
5449 if (!item->compare_done)
5450 item->chunk_size += CMP_SIZE;
5451 if (fail_tramp)
5452 item->chunk_size += BR_SIZE + JUMP_IMM32_SIZE;
5453 else
5454 item->chunk_size += BR_SIZE + JUMP_IMM_SIZE;
5455 } else {
5456 if (fail_tramp) {
5457 item->chunk_size += CMP_SIZE + BR_SIZE + JUMP_IMM32_SIZE * 2;
5458 } else {
5459 item->chunk_size += JUMP_IMM_SIZE;
5460 #if ENABLE_WRONG_METHOD_CHECK
5461 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5462 #endif
5465 } else {
5466 item->chunk_size += CMP_SIZE + BR_SIZE;
5467 imt_entries [item->check_target_idx]->compare_done = TRUE;
5469 size += item->chunk_size;
5471 if (fail_tramp) {
5472 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5473 } else {
5474 /* the initial load of the vtable address */
5475 size += 8;
5476 code = mono_domain_code_reserve (domain, size);
5478 start = code;
5479 if (!fail_tramp)
5480 ppc_load (code, ppc_r11, (guint32)(& (vtable->vtable [0])));
5481 for (i = 0; i < count; ++i) {
5482 MonoIMTCheckItem *item = imt_entries [i];
5483 item->code_target = code;
5484 if (item->is_equals) {
5485 if (item->check_target_idx) {
5486 if (!item->compare_done) {
5487 ppc_load (code, ppc_r0, (guint32)item->key);
5488 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
5490 item->jmp_code = code;
5491 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5492 if (fail_tramp)
5493 ppc_load (code, ppc_r0, item->value.target_code);
5494 else
5495 ppc_lwz (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r11);
5496 ppc_mtctr (code, ppc_r0);
5497 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5498 } else {
5499 if (fail_tramp) {
5500 ppc_load (code, ppc_r0, (guint32)item->key);
5501 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
5502 item->jmp_code = code;
5503 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5504 ppc_load (code, ppc_r0, item->value.target_code);
5505 ppc_mtctr (code, ppc_r0);
5506 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5507 ppc_patch (item->jmp_code, code);
5508 ppc_load (code, ppc_r0, fail_tramp);
5509 ppc_mtctr (code, ppc_r0);
5510 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5511 item->jmp_code = NULL;
5512 } else {
5513 /* enable the commented code to assert on wrong method */
5514 #if ENABLE_WRONG_METHOD_CHECK
5515 ppc_load (code, ppc_r0, (guint32)item->key);
5516 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
5517 item->jmp_code = code;
5518 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5519 #endif
5520 ppc_lwz (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r11);
5521 ppc_mtctr (code, ppc_r0);
5522 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5523 #if ENABLE_WRONG_METHOD_CHECK
5524 ppc_patch (item->jmp_code, code);
5525 ppc_break (code);
5526 item->jmp_code = NULL;
5527 #endif
5530 } else {
5531 ppc_load (code, ppc_r0, (guint32)item->key);
5532 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
5533 item->jmp_code = code;
5534 ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 0);
5537 /* patch the branches to get to the target items */
5538 for (i = 0; i < count; ++i) {
5539 MonoIMTCheckItem *item = imt_entries [i];
5540 if (item->jmp_code) {
5541 if (item->check_target_idx) {
5542 ppc_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
5547 if (!fail_tramp)
5548 mono_stats.imt_thunks_size += code - start;
5549 g_assert (code - start <= size);
5550 mono_arch_flush_icache (start, size);
5551 return start;
5552 #endif
5555 MonoMethod*
5556 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
5558 return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
5560 #endif
5562 MonoVTable*
5563 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
5565 NOT_IMPLEMENTED;
5566 return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];